• 【CF1528C】Trees of Tranquillity


    题目

    题目链接:https://codeforces.com/problemset/problem/1528/C
    给定两棵大小为 (n) 的树,以及 (n) 个点,点 (x,y) 之间会有连边当且仅当 (x,y) 在第一棵树上为祖孙关系,且在第二棵树上不是祖孙关系。
    求图的最大团。多测。
    (Q,sum nleq 3 imes 10^5)

    思路

    oisdoaiu CCCCCCCCOrz。
    等价于在第一棵树上 (1)(x) 的一条链上的所有点,选尽量多满足它们在第二棵树上的子树不交。
    在第一棵树上 dfs,当搜索到点 (x) 的时候,如果选出的祖先中有一个与 (x) 的子树有交集,肯定选择孙子最优。
    又因为题目保证每一个节点的父亲编号比他小,所以等价于肯定选 (x)
    那么我们需要实现的就是区间覆盖,单点查询,直接用树状数组维护即可。
    时间复杂度 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=300010;
    int Q,n,tot,ans,cnt,head[N],a[N],b[N],id[N],siz[N];
    
    struct edge
    {
    	int next,to;
    }e[N];
    
    void add(int from,int to)
    {
    	e[++tot]=(edge){head[from],to};
    	head[from]=tot;
    }
    
    struct BIT
    {
    	int c[N];
    	
    	void add(int x,int v)
    	{
    		for (int i=x;i<=n;i+=i&-i)
    			c[i]+=v;
    	}
    	
    	int query(int x)
    	{
    		int ans=0;
    		for (int i=x;i;i-=i&-i)
    			ans+=c[i];
    		return ans;
    	}
    }bit;
    
    void prework()
    {
    	tot=ans=cnt=0;
    	for (int i=1;i<=n;i++)
    		head[i]=-1,bit.c[i]=0;
    }
    
    void dfs1(int x)
    {
    	id[x]=++tot; siz[x]=1;
    	for (int i=head[x];~i;i=e[i].next)
    		dfs1(e[i].to),siz[x]+=siz[e[i].to];
    }
    
    void dfs2(int x)
    {
    	int y=bit.query(id[x]);
    	if (y) bit.add(id[y],-y),bit.add(id[y]+siz[y],y);
    		else cnt++,ans=max(ans,cnt);
    	bit.add(id[x],x); bit.add(id[x]+siz[x],-x);
    	for (int i=head[x];~i;i=e[i].next)
    		dfs2(e[i].to);
    	bit.add(id[x],-x); bit.add(id[x]+siz[x],x);
    	if (y) bit.add(id[y],y),bit.add(id[y]+siz[y],-y);
    		else cnt--;
    }
    
    void work()
    {
    	scanf("%d",&n);
    	for (int i=2;i<=n;i++) scanf("%d",&a[i]);
    	for (int i=2;i<=n;i++) scanf("%d",&b[i]);
    	prework();
    	for (int i=2;i<=n;i++) add(b[i],i);
    	tot=0; dfs1(1);
    	prework();
    	for (int i=2;i<=n;i++) add(a[i],i);
    	dfs2(1);
    	printf("%d
    ",ans);
    }
    
    int main()
    {
    	scanf("%d",&Q);
    	while (Q--) work();
    	return 0;
    }
    
  • 相关阅读:
    剑指offer-第二章排序之年龄排序
    剑指offer—第二章算法之快速排序
    java小程序(课堂作业02)
    关于java的一些小知识(课程作业01)
    Java从命令行接受多个数字并求和
    《大道至简》第一章读后感及伪代码
    大道至简读后感
    GCPC 2013_A Boggle DFS+字典树 CSU 1457
    Aizu 2155 Magic Slayer 背包DP
    UVALive 4255 Guess
  • 原文地址:https://www.cnblogs.com/stoorz/p/14807421.html
Copyright © 2020-2023  润新知