2021牛客多校7 F、xay loves trees

提供一种轻重链剖分+dp的做法

先把2树的lca预处理好,用下面这个方式查询可以省去上跳的时间(直接欧拉序也行,不过比赛的时候能想到欧拉序我就不会写dp了QAQ):

int lca(int u, int v)
{
    if (d[u] > d[v])swap(u, v);//默认v的深度较大
    while (d[v] > d[u])
        v = f[lg[d[v] - d[u]] - 1][v];//上跳2^(lg(深度差)-1步)
    if (u == v)return v;
    else
        return -1;
}

然后把1树重链预处理出来,每次首先沿着重链跑滑动窗口,暴力pop与新加入节点冲突的祖先节点。这样得到的答案能尽可能大,之后加上最优化剪支就可以不用搜索很多比较小的子树。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
#define pll pair<ll,ll>
const double PI = acos(-1);
const int inf = 2e9;
const ll lnf = 1e18 + 7;
const int maxn = 3e5 + 5;
const int N = 1 << 30 - 1;
ll mod = 998244353;
double eps = 1e-6;

int head[maxn], f[22][maxn], edge_cnt = 0, d[maxn];

int lg[maxn];

int S;

struct edge {
    int to, next;
}e[2 * maxn];

void add(int from, int to)
{
    e[++edge_cnt].to = to;
    e[edge_cnt].next = head[from];
    head[from] = edge_cnt;
}

void lg_init(int n)
{
    for (int i = 1; i <= n; i++)
    {
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);//1 2 2 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5(打表)
        //cout << lg[i] << " ";
    }
}//lg(i)数组实际意义:到根至多要跳lg(i)步;eg:lg(8)=4,8=2^3=1+2+4+1

void pre_lca(int from)
{
    //cout << from << endl;
    for (int i = 1; (1 << i) <= d[from]; i++)
        f[i][from] = f[i - 1][f[i - 1][from]];
    for (int i = head[from]; i; i = e[i].next)
    {
        int to = e[i].to;
        //cout << to << endl;
        if (to == f[0][from])continue;
        d[to] = d[from] + 1;//处理深度
        f[0][to] = from;//标记父节点
        pre_lca(to);
    }
}

int lca(int u, int v)
{
    if (d[u] > d[v])swap(u, v);//默认v的深度较大
    while (d[v] > d[u])
        v = f[lg[d[v] - d[u]] - 1][v];//上跳2^(lg(深度差)-1步)
    if (u == v)return v;
    else
        return -1;
}

vector<int>G[maxn];

vector<int>inq;
int ddfmax[maxn], ddf[maxn], siz[maxn], son[maxn];

int predfs(int now, int fa)
{
    siz[now] = 1;
    int maxson = -1;
    ddfmax[now] = ddf[now];
    int to;
    for (int i=0;i<G[now].size();i++)
    {
        to = G[now][i];
        if (to == fa)continue;
        ddf[to] = ddf[now] + 1;
        ddfmax[now] = max(ddfmax[now], predfs(to, now));
        siz[now] += siz[to];
        if (siz[to] > maxson)
            son[now] = to, maxson = siz[to];
    }
    return ddfmax[now];
}

int ans = 1;

pii getans(int from,int last)
{
    int sz = inq.size();
    int res = 1;
    int p = last;
    for (int i = sz - 2; i >= last; i--)
    {
        if (lca(inq[i], from) == -1)
            res++;
        else
        {
            p = i + 1;
            break;
        }
    }
    /*if (res != 1)
        for (int i = p; i < sz; i++)
            cout << inq[i] << " ";
    cout << endl;*/
    ans = max(res, ans);
    return make_pair(p, sz - p);
}

void dfs(int from, int fa, int last)
{
    inq.push_back(from);
    pii tmp = getans(from, last);
    if (!son[from])
    {
        inq.pop_back();
        return;
    }
    dfs(son[from], from, tmp.first);
    for (auto to : G[from])
    {
        if (to == fa || to == son[from])continue;
        if(ddfmax[from] - ddf[from]+ tmp.second > ans)
            dfs(to, from, tmp.first);
    }
    inq.pop_back();
}

int main()
{

    /*
    3
        5
        2 1
        2 5
        5 3
        2 4
        2 1
        1 5
        1 3
        3 4
        5
        5 3
        3 1
        5 4
        3 2
        5 3
        5 1
        3 4
        3 2
    */
	//fastio;
    lg_init(3e5);
    S = 1;
	int t;
    scanf("%d", &t);
	while (t--)
	{
        int n;
        scanf("%d", &n);
        //init
        edge_cnt = 0;
        ans = 1;
        while (inq.size() > 0)
            inq.pop_back();
        for (int i = 1; i <= n; i++)
            son[i] = 0, head[i] = -1, G[i].clear();

        int x, y;
        for (int i = 1; i < n; ++i)
        {
            scanf("%d %d", &x, &y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        for (int i = 1; i < n; ++i)
        {
            scanf("%d %d", &x, &y);
            add(x, y);
            add(y, x);
        }

        //preprocess
        d[1] = 0;
        f[0][S] = S;
        pre_lca(1);
        ddf[1] = 0;
        predfs(1, -1);

        //getans
        for (auto i : G[1])
            dfs(i, 1, 0);

        printf("%d\n", ans);
	}
        
	return 0;

}
上一篇:#插头dp#洛谷 5074 Eat the Trees


下一篇:openTSDB详解之Trees