zoukankan      html  css  js  c++  java
  • 【BZOJ4771】七彩树 主席树+树链的并

    【BZOJ4771】七彩树

    Description

    给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点。每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i]。如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色。定义depth[i]为i节点与根节点的距离,为了方便起见,你可以认为树上相邻的两个点之间的距离为1。站在这棵色彩斑斓的树前面,你将面临m个问题。每个问题包含两个整数x和d,表示询问x子树里且depth不超过depth[x]+d的所有点中出现了多少种本质不同的颜色。请写一个程序,快速回答这些询问。

    Input

    第一行包含一个正整数T(1<=T<=500),表示测试数据的组数。
    每组数据中,第一行包含两个正整数n(1<=n<=100000)和m(1<=m<=100000),表示节点数和询问数。
    第二行包含n个正整数,其中第i个数为c[i](1<=c[i]<=n),分别表示每个节点的颜色。
    第三行包含n-1个正整数,其中第i个数为f[i+1](1<=f[i]<i),表示节点i+1的父亲节点的编号。
    接下来m行,每行两个整数x(1<=x<=n)和d(0<=d<n),依次表示每个询问。
    输入数据经过了加密,对于每个询问,如果你读入了x和d,那么真实的x和d分别是x xor last和d xor last,
    其中last表示这组数据中上一次询问的答案,如果这是当前数据的第一组询问,那么last=0。
    输入数据保证n和m的总和不超过500000。

    Output

    对于每个询问输出一行一个整数,即答案。

    Sample Input

    1
    5 8
    1 3 3 2 2
    1 1 3 3
    1 0
    0 0
    3 0
    1 3
    2 1
    2 0
    6 2
    4 1

    Sample Output

    1
    2
    3
    1
    1
    2
    1
    1

    题解:先不考虑深度的限制。我们分别考虑每种颜色。

    如果这个颜色只有一个点,那么它对它的所有祖先的贡献都是1,如果有2个点a,b,那么它们对a和b的祖先贡献都是1,其中两者lca的祖先被重复计算了1次,要将它减去。

    以此类推,这些点对它们的树链的并的贡献都是1,所以求出树链的并,用线段树维护子树权值和即可。

    但是如果考虑深度限制呢?将线段树改成主席树即可,即对于每个深度都维护一棵线段树。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <set>
    using namespace std;
    const int maxn=100010;
    int n,m,cnt,tot,ans;
    set<int> S[maxn];
    set<int>::iterator it;
    int to[maxn],next[maxn],head[maxn],fa[19][maxn],dep[maxn],Log[maxn],p[maxn],q[maxn],pd[maxn],Q[maxn],rt[maxn],v[maxn];
    struct node
    {
    	int ls,rs,siz;
    }s[maxn*50];
    void dfs(int x)
    {
    	p[x]=++q[0],Q[q[0]]=x;
    	for(int i=head[x];i!=-1;i=next[i])	dep[to[i]]=dep[x]+1,dfs(to[i]);
    	q[x]=q[0];
    }
    inline int lca(int a,int b)
    {
    	if(dep[a]<dep[b])	swap(a,b);
    	for(int i=Log[dep[a]-dep[b]];i>=0;i--)	if(dep[fa[i][a]]>=dep[b])	a=fa[i][a];
    	if(a==b)	return a;
    	for(int i=Log[dep[a]];i>=0;i--)	if(fa[i][a]!=fa[i][b])	a=fa[i][a],b=fa[i][b];
    	return fa[0][a];
    }
    bool cmp(int a,int b)
    {
    	return dep[a]<dep[b];
    }
    void insert(int x,int &y,int l,int r,int a,int b)
    {
    	y=++tot,s[y].ls=s[y].rs=s[y].siz=0;
    	s[y].siz=s[x].siz+b;
    	if(l==r)	return ;
    	int mid=(l+r)>>1;
    	if(a<=mid)	s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,a,b);
    	else	s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,a,b);
    }
    int query(int l,int r,int x,int a,int b)
    {
    	if(!x||(a<=l&&r<=b))	return s[x].siz;
    	int mid=(l+r)>>1;
    	if(b<=mid)	return query(l,mid,s[x].ls,a,b);
    	if(a>mid)	return query(mid+1,r,s[x].rs,a,b);
    	return query(l,mid,s[x].ls,a,b)+query(mid+1,r,s[x].rs,a,b);
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    inline void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    void work()
    {
    	n=rd(),m=rd(),tot=cnt=ans=q[0]=0;
    	int i,j,a,b;
    	memset(head,-1,sizeof(head));
    	memset(rt,0,sizeof(rt));
    	memset(fa,0,sizeof(fa));
    	for(i=1;i<=n;i++)	v[i]=rd(),S[i].clear(),pd[i]=i;
    	for(i=2;i<=n;i++)	fa[0][i]=rd(),add(fa[0][i],i),Log[i]=Log[i>>1]+1;
    	dep[1]=1,dfs(1);
    	for(j=1;(1<<j)<=n;j++)	for(i=1;i<=n;i++)	fa[j][i]=fa[j-1][fa[j-1][i]];
    	sort(pd+1,pd+n+1,cmp);
    	for(i=1;i<=n;i++)
    	{
    		j=pd[i],a=b=0,it=S[v[j]].lower_bound(p[j]);
    		insert(rt[dep[pd[i-1]]],rt[dep[j]],1,n,p[j],1);
    		if(it!=S[v[j]].end())	b=Q[(*it)],insert(rt[dep[j]],rt[dep[j]],1,n,p[lca(b,j)],-1);
    		if(it!=S[v[j]].begin())	it--,a=Q[(*it)],insert(rt[dep[j]],rt[dep[j]],1,n,p[lca(a,j)],-1);
    		if(a&&b)	insert(rt[dep[j]],rt[dep[j]],1,n,p[lca(a,b)],1);
    		S[v[j]].insert(p[j]);
    	}
    	for(i=1;i<=m;i++)
    	{
    		a=rd()^ans,b=rd()^ans;
    		ans=query(1,n,rt[min(dep[a]+b,dep[pd[n]])],p[a],q[a]);
    		printf("%d
    ",ans);
    		//ans=0;
    	}
    }
    int main()
    {
    	int T=rd();
    	while(T--)	work();
    	return 0;
    }//1 4 4 4 2 3 2  1 2 1  3 2 2 2 4 1 4 1 
  • 相关阅读:
    python基础(二)
    python基础(一)
    SQL的四种连接-左外连接、右外连接、内连接、全连接
    mysql常用操作
    jenkins邮件通知功能
    mysql常用命令
    SQL优化法则小记
    架构漫谈
    今日头条的成功史
    python连接mysql数据库简单例子
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7629200.html
Copyright © 2011-2022 走看看