bzoj4771 七彩树 可持久化线段树+set
作者:互联网
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的所有点中出现了多少种本质不同的颜色
。请写一个程序,快速回答这些询问。
Solution
之前做过类似的题目吧
一个颜色的贡献是1,我们用set维护dfs序,插入的时候减去dfs序相邻点lca的贡献,就变成二维数点问题了。
没有修改所有按深度建可持久化线段树就可以了
求lca要rmq不然会多一个log(虽然多一个log好像也能跑得过
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <set>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
const int N=200005;
struct edge {int y,next;} e[N*2];
struct treeNode {int l,r,sum;} t[N*81];
std:: set <pair> set[N];
int fa[N],dep[N],pos[N],size[N];
int rt[N],rec[N],mn[21][N],c[N];
int ls[N],p[N],edCnt,tot;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
}
void modify(int &now,int pre,int tl,int tr,int x,int v) {
t[now=++tot]=t[pre]; t[now].sum+=v;
if (tl==tr) return ;
int mid=(tl+tr)>>1;
if (x<=mid) modify(t[now].l,t[pre].l,tl,mid,x,v);
else modify(t[now].r,t[pre].r,mid+1,tr,x,v);
}
int query(int now,int tl,int tr,int l,int r) {
if (r<l||!now) return 0;
if (tl>=l&&tr<=r) return t[now].sum;
int mid=(tl+tr)>>1;
int qx=query(t[now].l,tl,mid,l,std:: min(r,mid));
int qy=query(t[now].r,mid+1,tr,std:: max(mid+1,l),r);
return qx+qy;
}
void dfs(int x) {
pos[x]=++pos[0];
mn[0][++rec[0]]=x;
rec[x]=rec[0];
size[x]=1;
for (int i=ls[x];i;i=e[i].next) {
dep[e[i].y]=dep[x]+1;
dfs(e[i].y); size[x]+=size[e[i].y];
mn[0][++rec[0]]=x;
}
}
int get_lca(int x,int y) {
x=rec[x],y=rec[y];
if (x>y) std:: swap(x,y);
int lg=log2(y-x+1);
int qx=mn[lg][x],qy=mn[lg][y-(1<<lg)+1];
return (dep[qx]<dep[qy])?qx:qy;
}
void clr() {
fill(ls,0); edCnt=tot=0;
fill(pos,0); fill(size,0);
fill(rec,0); fill(dep,0);
fill(rt,0);
}
bool cmp(int x,int y) {
return dep[x]<dep[y];
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int T=read();
for (;T--;clr()) {
int n=read(),m=read();
rep(i,1,n) set[i].clear();
rep(i,1,n) c[i]=read();
rep(i,2,n) {
fa[i]=read();
add_edge(fa[i],i);
}
dfs(1);
rep(j,1,20) {
int len=1<<j-1;
rep(i,1,rec[0]-len+1) {
if (dep[mn[j-1][i]]<dep[mn[j-1][i+len]]) {
mn[j][i]=mn[j-1][i];
} else mn[j][i]=mn[j-1][i+len];
}
}
rep(i,1,n) p[i]=i;
std:: sort(p+1,p+n+1,cmp);
rep(i,1,n) {
int x=p[i];
if (dep[x]!=dep[p[i-1]]) rt[dep[x]]=rt[dep[p[i-1]]];
set[c[x]].insert(pair(pos[x],x));
std:: set <pair>:: iterator it=set[c[x]].find(pair(pos[x],x));
int nex=0,pre=0;
it++; if (it!=set[c[x]].end()) nex=(*it).se; it--;
if (it!=set[c[x]].begin()) it--,pre=(*it).se,it++;
modify(rt[dep[x]],rt[dep[x]],1,n,pos[x],1);
if (pre) modify(rt[dep[x]],rt[dep[x]],1,n,pos[get_lca(x,pre)],-1);
if (nex) modify(rt[dep[x]],rt[dep[x]],1,n,pos[get_lca(x,nex)],-1);
if (nex&&pre) modify(rt[dep[x]],rt[dep[x]],1,n,pos[get_lca(nex,pre)],1);
}
rep(i,1,n) if (!rt[i]) rt[i]=rt[i-1];
for (int x,d,w,lastans=0;m--;) {
x=read(),d=read();
// x=read()^lastans,d=read()^lastans;
w=std:: min(dep[x]+d,n);
lastans=query(rt[w],1,n,pos[x],pos[x]+size[x]-1);
printf("%d\n", lastans);
}
}
return 0;
}
标签:rt,pre,七彩,set,bzoj4771,int,pos,dep 来源: https://blog.csdn.net/jpwang8/article/details/88283239