【BZOJ4154】[Ipsc2015]Generating Synergy
Description
给定一棵以1为根的有根树,初始所有节点颜色为1,每次将距离节点a不超过l的a的子节点染成c,或询问点a的颜色
Input
第一行一个数T,表示数据组数
接下来每组数据的第一行三个数n,c,q表示结点个数,颜色数和操作数
接下来一行n-1个数描述2..n的父节点
接下来q行每行三个数a,l,c
若c为0,表示询问a的颜色
否则将距离a不超过l的a的子节点染成c
Output
设当前是第i个操作,y_i为本次询问的答案(若本次操作是一个修改则y_i为0),令z_i=i*y_i,请输出z_1+z_2+...+z_q模10^9+7
Sample Input
1
4 3 7
1 2 2
3 0 0
2 1 3
3 0 0
1 0 2
2 0 0
4 1 1
4 0 0
4 3 7
1 2 2
3 0 0
2 1 3
3 0 0
1 0 2
2 0 0
4 1 1
4 0 0
Sample Output
32
HINT
第1,3,5,7的询问的答案分别为1,3,3,1,所以答案为 1*1+2*0+3*3+4*0+5*3+6*0+7*1=32.
数据范围:
对于100%的数据T<=6,n,m,c<=10^5,
1<=a<=n,0<=l<=n,0<=c<=c
题解:想了半天奇怪的做法,正解居然是KDtree?
KDtree的第一维是DFS序,第二维是深度,区间修改用打标记实现,查询时下传标记,剩下的就不用说了吧?
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const ll P=1000000007; const int maxn=100010; int n,m,D,rt,cnt; ll ans; int to[maxn],next[maxn],head[maxn],p[maxn],q[maxn],fa[maxn],L[2],R[2],dep[maxn],st[maxn],pos[maxn]; struct kd { int ls,rs,fa,tag,col,org,v[2],sm[2],sn[2]; kd(){} kd(int a,int b,int c){sm[0]=sn[0]=v[0]=a,sm[1]=sn[1]=v[1]=b,org=c,ls=rs=fa=0,tag=0,col=1;} }t[maxn]; bool cmp(const kd &a,const kd &b) { return (a.v[D]==b.v[D])?(a.v[D^1]<b.v[D^1]):(a.v[D]<b.v[D]); } 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 dfs(int x) { p[x]=++p[0]; for(int i=head[x];i!=-1;i=next[i]) dep[to[i]]=dep[x]+1,dfs(to[i]); q[x]=p[0]; } inline void pushup(int x,int y) { t[x].sm[0]=max(t[x].sm[0],t[y].sm[0]); t[x].sn[0]=min(t[x].sn[0],t[y].sn[0]); t[x].sm[1]=max(t[x].sm[1],t[y].sm[1]); t[x].sn[1]=min(t[x].sn[1],t[y].sn[1]); } inline void pushdown(int x) { if(t[x].tag) { if(t[x].ls) t[t[x].ls].col=t[t[x].ls].tag=t[x].tag; if(t[x].rs) t[t[x].rs].col=t[t[x].rs].tag=t[x].tag; t[x].tag=0; } } int build(int l,int r,int d) { if(l>r) return 0; int mid=(l+r)>>1; D=d,nth_element(t+l,t+mid,t+r+1,cmp),pos[t[mid].org]=mid; t[mid].ls=build(l,mid-1,d^1),t[mid].rs=build(mid+1,r,d^1); if(t[mid].ls) t[t[mid].ls].fa=mid,pushup(mid,t[mid].ls); if(t[mid].rs) t[t[mid].rs].fa=mid,pushup(mid,t[mid].rs); return mid; } void updata(int x,int y) { if(!x||t[x].sn[0]>R[0]||t[x].sm[0]<L[0]||t[x].sn[1]>R[1]||t[x].sm[1]<L[1]) return ; pushdown(x); if(t[x].sm[0]<=R[0]&&t[x].sn[0]>=L[0]&&t[x].sm[1]<=R[1]&&t[x].sn[1]>=L[1]) { t[x].tag=t[x].col=y; return ; } if(t[x].v[0]<=R[0]&&t[x].v[0]>=L[0]&&t[x].v[1]<=R[1]&&t[x].v[1]>=L[1]) t[x].col=y; updata(t[x].ls,y),updata(t[x].rs,y); } inline int query(int x) { st[st[0]=1]=x; while(t[st[st[0]]].fa) st[st[0]+1]=t[st[st[0]]].fa,st[0]++; while(st[0]) pushdown(st[st[0]]),st[0]--; return t[x].col; } void work() { n=rd(),rd(),m=rd(); memset(head,-1,sizeof(head)),cnt=0,ans=0; int i,a,b,c; for(i=2;i<=n;i++) fa[i]=rd(),add(fa[i],i); dep[1]=1,dfs(1); for(i=1;i<=n;i++) t[i]=kd(p[i],dep[i],i); rt=build(1,n,0); for(i=1;i<=m;i++) { a=rd(),b=rd(),c=rd(); if(!c) ans=(ans+(ll)i*query(pos[a]))%P; else L[0]=p[a],R[0]=q[a],L[1]=dep[a],R[1]=dep[a]+b,updata(rt,c); } printf("%lld ",ans); } int main() { int T=rd(); while(T--) work(); return 0; }//1 4 3 7 1 2 2 3 0 0 2 1 3 3 0 0 1 0 2 2 0 0 4 1 1 4 0 0