1 条题解

  • 1
    @ 2022-3-3 13:16:06

    vp 时写了 1.5h 才过的题,看来我还是太逊了。

    来发树状数组题解。

    洛谷中有一篇树状数组题解,可惜被我 hack 掉了。

    先考虑满足第一棵树的性质,必然需要满足所选的点在一条链上。

    然后贪心去取,如果当前选的点和之前的点矛盾,就把之前的去掉。

    一个性质是每次最多去掉一个点,否则在加入这个点之前就矛盾了。

    树状数组维护一下 dfs 序,判断是否矛盾。

    注意判断矛盾既要判断自己是否在别的点的子树中,也需要判断别的是否在自己的子树中。


    代码
    #include<bits/stdc++.h>
    using namespace std;
    const int N=3e5+5;
    int in[N],out[N],c[2][N],fa[N],dep[N],n,ti;
    vector<int> e[N],tr[N];
    void dfs1(int x){
    	in[x]=++ti;
    	for(int y:tr[x])dfs1(y);
    	out[x]=ti;
    }
    void dfs(int x){for(int y:e[x])dep[y]=dep[x]+1,dfs(y);}
    void add(int p,int x,int z){for(;x<=n;x+=x&-x)c[p][x]+=z;}
    int ask(int p,int x){if(!x)return 0;int ans=0;for(;x;x-=x&-x)ans+=c[p][x];return ans;}
    void add(int x){
    	add(0,in[x],x),add(0,out[x]+1,-x);
    	add(1,in[x],x);
    }
    void del(int x){
    	add(0,in[x],-x),add(0,out[x]+1,x);
    	add(1,in[x],-x);
    }
    int ans=0,sum=0;
    void dfs2(int x){
    	int t,ff=0;
    	if(t=ask(0,in[x]))del(t),sum--,ff=t;
    	if(t=ask(1,out[x])-ask(1,in[x]-1))del(t),sum--,ff=t;
    	add(x),sum++;
    	ans=max(ans,sum);
    	for(int y:e[x])dfs2(y);
    	del(x),sum--;
    	if(ff)add(ff),sum++;
    }
    void work(){
    	ans=sum=0;
    	scanf("%d",&n);
    	for(int i=2;i<=n;i++)scanf("%d",&fa[i]),e[fa[i]].push_back(i);
    	for(int i=2,x;i<=n;i++)scanf("%d",&x),tr[x].push_back(i);
    	dfs1(1);
    	dfs(1);
    	dfs2(1);
    	printf("%d\n",ans);
    	for(int i=1;i<=n;i++)e[i].clear(),tr[i].clear(),dep[i]=0;
    	ti=0;
    }
    int _;
    int main(){
    	scanf("%d",&_);
    	while(_--)work();
    }
    
    • 1

    信息

    ID
    86
    时间
    3000ms
    内存
    256MiB
    难度
    (无)
    标签
    递交数
    0
    已通过
    0
    上传者