把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

BZOJ #4771. 七彩树

题面传送门
像个sb一样写了树套树然后又卡空间又卡时间。
首先我们考虑一下没有深度限制怎么做。
考虑把每种颜色都拿出来建一棵斯坦纳树,所以斯坦纳树上的所有点都有这种颜色的一个贡献。
具体的,维护每个点最近的两个点的dfs序然后每个点加一,lca处减一即可。查询只要查dfs序上子树和即可。
现在是考虑深度,那么以深度为下标建立主席树即可。
时间复杂度\(O(nlogn)\)
code:

#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define l(x) x<<1
#define r(x) x<<1|1
#define re register
#define ll long long
#define db long double
#define N 100000
#define eps (1e-14)
#define mod 73946381
#define U unsigned
using namespace std;
int n,m,k,x,y,z,d[N+5],siz[N+5],fa[N+5][20],lg[N+5],col[N+5],root[N+5<<1],lastans,net,las,dh,dfn[N+5],T,cnt,now,st[N+5];vector<int> g[N+5<<1];set<int> fs[N+5]; 
set<int>::iterator it;struct yyy{int to,z;};
struct ljb{
	int head,h[N+5];yyy f[N+5];
	I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}
}s;
I void dfs(int x,int last){
	dfn[x]=++dh;st[dh]=x;d[x]=d[last]+1;yyy tmp;fa[x][0]=last;for(int i=1;i<=lg[d[x]];i++) fa[x][i]=fa[fa[x][i-1]][i-1];
	siz[x]=1;for(int i=s.h[x];i;i=tmp.z) tmp=s.f[i],dfs(tmp.to,x),siz[x]+=siz[tmp.to];
}
I void swap(int &x,int &y){x^=y^=x^=y;}
I int lca(int x,int y){
	d[x]<d[y]&&(swap(x,y),0);while(d[x]^d[y]) x=fa[x][lg[d[x]-d[y]]];if(x==y) return x;
	for(int i=lg[d[x]];~i;i--) fa[x][i]^fa[y][i]&&(x=fa[x][i],y=fa[y][i]);return fa[x][0];
}
struct tree{
	int ls[N+5<<6],rs[N+5<<6],f[N+5<<6],cnt;
	I void clear(){memset(ls,0,cnt+1);memset(rs,0,cnt+1);memset(f,0,cnt+1);cnt=0;}
	I void get(int x,int y,int &now,int l=1,int r=n){
		ls[++cnt]=ls[now];rs[cnt]=rs[now];f[cnt]=f[now]+y;now=cnt;if(l==r) return;
		int m=l+r>>1;x<=m?get(x,y,ls[now],l,m):get(x,y,rs[now],m+1,r);
	}
	I int find(int x,int y,int now,int l=1,int r=n){
		if(!now) return 0;if(x<=l&&r<=y) return f[now];int m=l+r>>1,fs=0;
		x<=m&&(fs+=find(x,y,ls[now],l,m));y>m&&(fs+=find(x,y,rs[now],m+1,r));return fs;
	}
}f;
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	re int i,j;scanf("%d",&T);for(i=2;i<=N;i++) lg[i]=lg[i/2]+1;while(T--){
		s.head=0;f.clear();lastans=0;for(i=1;i<=n;i++) g[i].clear(),fs[i].clear(),s.h[i]=0;dh=0;
		scanf("%d%d",&n,&m);for(i=1;i<=n;i++) scanf("%d",&col[i]);for(i=2;i<=n;i++) scanf("%d",&x),s.add(x,i);dfs(1,0);
		for(i=1;i<=n;i++) g[d[i]].push_back(i);for(i=1;i<=2*n;i++){
			root[i]=root[i-1];for(j=0;j<g[i].size();j++){
				now=g[i][j];f.get(dfn[now],1,root[i]);it=fs[col[now]].lower_bound(dfn[now]);net=las=0;//printf("ins %d %d\n",dfn[now],col[now]);
				if(it!=fs[col[now]].end())f.get(dfn[lca(now,net=st[*it])],-1,root[i])/*,printf("del %d %d\n",dfn[lca(now,net)],col[now])1*/;
				if(it!=fs[col[now]].begin()) f.get(dfn[lca(now,las=st[*--it])],-1,root[i])/*,printf("del %d %d\n",dfn[lca(now,las)],col[now])*/;
				if(las&&net) f.get(dfn[lca(las,net)],1,root[i])/*,printf("ins %d %d\n",dfn[lca(las,net)],col[now])*/;fs[col[now]].insert(dfn[now]);
			}
		}
		for(i=1;i<=m;i++) 
		scanf("%d%d",&x,&y),x^=lastans,y^=lastans,printf("%d\n",lastans=f.find(dfn[x],dfn[x]+siz[x]-1,root[d[x]+y]));
	}
}//4410 44
posted @ 2021-06-05 19:55  275307894a  阅读(44)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end