zoukankan      html  css  js  c++  java
  • bzoj 4771: 七彩树

    4771: 七彩树

    Time Limit: 5 Sec  Memory Limit: 256 MB
    Submit: 1334  Solved: 388
    [Submit][Status][Discuss]

    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

    HINT

     

    Source

     
        非常经典的一道题,相当于是把序列上的区间颜色数 放到了树上,并且是加强版。
        考虑序列上的区间颜色数求法,(只考虑在线的话)我们是用可持久化线段树实现的每种颜色不会重复加;
        如果只是简单的放到树上,没有深度限制的话,直接通过dfs序转换成序列上的求就行了,也很简单。。。。
       
        所以这个深度限制是什么鬼啊QWQ
        这个时候只能换一种思路啦。
        考虑把节点按照深度从小到大一层一层加进去,我们加入一个节点的时候要保证,此时以任意一个节点为根的子树中,这种颜色只会被算一次。
        这该怎么做呢????
     
        当这个节点x是这种颜色第一个加入的节点,那么显然只需要在这个节点的dfs序上+1就行了;
        如果有其他的节点,因为我们已经保证了不考虑这个节点的时候的任意子树,每种颜色只会被算一次,所以我们只需要考虑  子树中包含这个节点x 并且 原来已经有这种颜色的 点。设pre是该颜色的点中dfs序小于x的dfs序最大的节点,nxt是。。。。大于x的。。。最小的点,那么LCA(x,nxt)--,LCA(x,pre),LCA(pre,nxt)++就行啦(请自行画图草稿)
     
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    #define pb push_back
    #define mid (l+r>>1)
    const int maxn=100005;
    set<int> s[maxn];
    vector<int> g[maxn];
    set<int> :: iterator it;
    int dfn[maxn],dy[maxn],siz[maxn],son[maxn],L;
    int n,m,to[maxn],ne[maxn],hd[maxn],num,col[maxn];
    int F[maxn],T,cl[maxn],dc,le,ri,w,M,dep[maxn],ans;
    struct node{
    	int S;
    	node *lc,*rc;
    }nil[maxn*123],*rot[maxn],*cnt;
    
    inline int read(){
    	int x=0; char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar());
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    	return x;
    }
    void W(int x){ if(x>=10) W(x/10); putchar(x%10+'0');}
    
    inline void init(){
    	fill(hd+1,hd+n+1,0),num=0;
    	for(int i=1;i<=M;i++) g[i].clear(); 
    	fill(son+1,son+n+1,0),M=0;dc=0;
    	cnt=nil->lc=nil->rc=rot[0]=nil;
    	for(int i=1;i<=n;i++) s[i].clear();
    }
    
    inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}
    
    void Fdfs(int x){
    	siz[x]=1,M=max(M,dep[x]),g[dep[x]].pb(x);
    	for(int i=hd[x];i;i=ne[i]){
    		dep[to[i]]=dep[x]+1,Fdfs(to[i]);
    		siz[x]+=siz[to[i]];
    		if(!son[x]||siz[to[i]]>siz[son[x]]) son[x]=to[i];
    	}
    }
    
    void Sdfs(int x,int tp){
    	cl[x]=tp,dfn[x]=++dc,dy[dc]=x;
    	if(!son[x]) return;
    	
    	Sdfs(son[x],tp);
    	
    	for(int i=hd[x];i;i=ne[i]) if(to[i]!=son[x]) Sdfs(to[i],to[i]); 
    }
    
    int LCA(int x,int y){
    	while(cl[x]!=cl[y]){
    		if(dep[cl[x]]>dep[cl[y]]) x=F[cl[x]];
    		else y=F[cl[y]];
    	}
    	
    	return dep[x]>dep[y]?y:x;
    }
    
    node *update(node *u,int l,int r){
    	node *ret=++cnt;
    	*ret=*u,ret->S+=w;
    	if(l==r) return ret;
    	
    	if(le<=mid) ret->lc=update(ret->lc,l,mid);
    	else ret->rc=update(ret->rc,mid+1,r);
    	
    	return ret;
    }
    
    void query(node *u,int l,int r){
    	if(l>=le&&r<=ri){ ans+=u->S; return;}
    	if(le<=mid) query(u->lc,l,mid);
    	if(ri>mid) query(u->rc,mid+1,r);
    }
    
    inline void solve(){
    	dep[1]=1,Fdfs(1),Sdfs(1,1);
    	
    	for(int i=1;i<=M;i++){
    		rot[i]=rot[i-1];
    		
    	    for(int j=g[i].size()-1,now;j>=0;j--){
    	    	now=g[i][j];
    	    	le=dfn[now],w=1,rot[i]=update(rot[i],1,n);
    	    	
    	    	if(s[col[now]].size()){
    	    		it=s[col[now]].upper_bound(dfn[now]);
    	    		if(it==s[col[now]].end()) le=dfn[LCA(now,dy[*(--it)])],w=-1,rot[i]=update(rot[i],1,n);
    	    		else if(it==s[col[now]].begin()) le=dfn[LCA(now,dy[*it])],w=-1,rot[i]=update(rot[i],1,n);
    	    		else{
    	    			int nxt=dy[*it],pre=dy[*(--it)];
    	    			le=dfn[LCA(now,nxt)],w=-1,rot[i]=update(rot[i],1,n);
    	    			le=dfn[LCA(now,pre)],w=-1,rot[i]=update(rot[i],1,n);
    	    			le=dfn[LCA(pre,nxt)],w=1,rot[i]=update(rot[i],1,n);
    				}
    			}
    			
    			s[col[now]].insert(dfn[now]);
    		}
    	}
    	
    	while(m--){
    		le=read()^ans,L=read()^ans,ans=0;
    		L=min(M,dep[le]+L),ri=dfn[le]+siz[le]-1,le=dfn[le];
    		query(rot[L],1,n),W(ans),puts("");
    	}
    }
    
    int main(){
    //	freopen("data.in","r",stdin);
    //	freopen("data.out","w",stdout);
    	
    	T=read();
    	
    	while(T--){
    		init(),n=read(),m=read();
    		for(int i=1;i<=n;i++) col[i]=read();
    		for(int i=2;i<=n;i++) F[i]=read(),add(F[i],i);
    		solve();
    	}
    	
    	return 0;
    }
    

      

  • 相关阅读:
    单例模式
    HashSet、LinkedHashSet、SortedSet、TreeSet
    ArrayList、LinkedList、CopyOnWriteArrayList
    HashMap、Hashtable、LinkedHashMap
    andrew ng machine learning week8 非监督学习
    andrew ng machine learning week7 支持向量机
    andrew ng machine learning week6 机器学习算法理论
    andrew ng machine learning week5 神经网络
    andrew ng machine learning week4 神经网络
    vue组件监听属性变化watch方法报[Vue warn]: Method "watch" has type "object" in the component definition. Did you reference the function correctly?
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9062645.html
Copyright © 2011-2022 走看看