zoukankan      html  css  js  c++  java
  • BZOJ4771 七彩树

    题目

    给定一棵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的所有点中出现了多少种本质不同的颜色。请写一个程序,快速回答这些询问。

    思路

    本质与HDU3333Turing Tree是一样的,方法是可持久化线段树合并。

    每个点开一个线段树,保存当前子树下每个深度的颜色数

    再开一棵线段树,保存当前子树下每个颜色最浅的深度

    在进行线段树合并时要注意当两棵树中存在相同颜色时,取较浅的一个,把深的颜色删去,代码比较难调。

    需要注意的是,每次删除的操作都要新加节点,不能直接在原来的点上改,需要可持久化的思想。

    代码

    #include<bits/stdc++.h>
    #define M 100005
    #define clr(x,y) memset(x,y,sizeof(x))
    using namespace std;
    int T,n,m,A[M],h[M],tot,dep[M],inf;
    struct edge{
    	int nxt,to;
    }G[M<<1];
    void Add(int a,int b){
    	G[++tot]=(edge){h[a],b};
    	h[a]=tot;
    }
    int Lson[M*180],Rson[M*180],cnt[M*180],ver[M],tt;
    void Insert1(int &p,int x,int d,int L,int R){
    	cnt[++tt]=cnt[p];Lson[tt]=Lson[p];Rson[tt]=Rson[p];p=tt;	
    	cnt[p]+=d;
    	if(L==R)return;
    	int mid=(L+R)>>1;
    	if(x<=mid)Insert1(Lson[p],x,d,L,mid);
    	else Insert1(Rson[p],x,d,mid+1,R);
    }
    void merge1(int& x,int y,int L,int R){
    	if(!x||!y){x=(x|y);return;}
    	cnt[++tt]=cnt[x];Lson[tt]=Lson[x];Rson[tt]=Rson[x];x=tt;
    	if(L==R){cnt[x]+=cnt[y];return;}
    	int mid=(L+R)>>1;
    	merge1(Lson[x],Lson[y],L,mid);
    	merge1(Rson[x],Rson[y],mid+1,R);
    	cnt[x]=cnt[Lson[x]]+cnt[Rson[x]];
    }
    int query(int l,int r,int p,int L,int R){
    //	cout<<l<<' '<<r<<' '<<p<<' '<<L<<' '<<R<<endl;
    	if(!p)return 0;
    	if(l==L&&r==R)return cnt[p];
    	int mid=(L+R)>>1;
    	if(r<=mid)return query(l,r,Lson[p],L,mid);
    	else if(l>mid)return query(l,r,Rson[p],mid+1,R);
    	return query(l,mid,Lson[p],L,mid)+query(mid+1,r,Rson[p],mid+1,R); 
    }
    int lson[M*25],rson[M*25],dp[M*25],rt[M],ttt;
    void Insert2(int &p,int x,int d,int L,int R){
    	if(!p)p=++ttt,lson[p]=rson[p]=0,dp[p]=1e9;
    	if(L==R){dp[p]=min(dp[p],d);return;}
    	int mid=(L+R)>>1;
    	if(x<=mid)Insert2(lson[p],x,d,L,mid);
    	else Insert2(rson[p],x,d,mid+1,R); 
    }
    void merge2(int &x,int y,int L,int R,int& p){
    	if(!x||!y){x=(x|y);return;}
    	if(L==R){
    		Insert1(p,max(dp[x],dp[y]),-1,1,n);
    		dp[x]=min(dp[x],dp[y]);
    		return;
    	}
    	int mid=(L+R)>>1;
    	merge2(lson[x],lson[y],L,mid,p);
    	merge2(rson[x],rson[y],mid+1,R,p);
    }
    int last=0;
    int main(){
    	cin>>T;
    	while(T--){
    		clr(h,0);tot=ttt=tt=last=0;
    		clr(rt,0);clr(ver,0);cnt[0]=0;dp[0]=1e9;Lson[0]=Rson[0]=lson[0]=rson[0]=0;
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=n;i++)scanf("%d",&A[i]);
    		dep[1]=1;
    		for(int i=2,f;i<=n;i++)scanf("%d",&f),Add(f,i),dep[i]=dep[f]+1;
    		for(int i=n;i>=1;i--){
    			Insert1(ver[i],dep[i],1,1,n);
    			Insert2(rt[i],A[i],dep[i],1,n);
    			for(int j=h[i];j;j=G[j].nxt){
    				int u=G[j].to;
    				merge1(ver[i],ver[u],1,n);
    				merge2(rt[i],rt[u],1,n,ver[i]);
    			}
    		}
    		for(int i=1,x,d;i<=m;i++){
    			scanf("%d%d",&x,&d);
    			x=x^last;d=d^last;
    			printf("%d
    ",last=query(dep[x],min(n,dep[x]+d),ver[x],1,n));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    注册登录
    ASP.NET常用编程代码(一)
    HTML、CSS、JS、PHP 的学习顺序~(零基础初学者)
    如何学习javascript?(转)
    如何完全卸载SQL Server 2005
    如何给网页标题栏上添加图标(favicon.ico)
    网页制作常用代码
    网页颜色代码对照表
    ASP.NET常用编程代码(二)
    50个PHOTOSHOP快捷键技能!
  • 原文地址:https://www.cnblogs.com/zryabc/p/10356342.html
Copyright © 2011-2022 走看看