【BZOJ4154】Generating Synergy【kd树】

时间:2024-05-07 14:04:02

题意

给定一棵以1为根的有根树,初始所有节点颜色为1,每次将距离节点a不超过l的a的子节点染成c,或询问点a的颜色

分析

我们以dfs序为横坐标,深度为纵坐标,建kd树。我们每次更新,都是在kd树中更新一个矩形,横坐标为[st[a],en[a]],纵坐标[depth[a],depth[a]+l]。那么就相当于线段树的区间更新,我们需要给它打个标记。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream> using namespace std;
typedef long long LL;
const int maxn=1e5+;
const int INF=;
const int mod=1e9+; int n,q,c,sz,T;
int head[maxn],Next[*maxn],to[*maxn];
int cnt;
int order[maxn],indx[maxn],st[maxn],en[maxn],depth[maxn];
struct kdNode{
int x[],mnn[],mxn[];
int lc,rc,u;
int val,tag;
}p[maxn],x;
int cmpNo,root;
int cmp(kdNode a,kdNode b){
return a.x[cmpNo]<b.x[cmpNo];
}
void pushdown(int o){
if(p[o].tag){
int l=p[o].lc,r=p[o].rc;
p[l].val=p[o].tag,p[r].val=p[o].tag;
p[o].tag=;
}
} void maintain(int o){
int l=p[o].lc,r=p[o].rc;
for(int i=;i<;i++){
p[o].mnn[i]=min(min(p[l].mnn[i],p[r].mnn[i]),p[o].x[i]);
p[o].mxn[i]=max(max(p[l].mxn[i],p[r].mxn[i]),p[o].x[i]);
}
}
void build(int &o,int l,int r,int d){
if(l>r){
o=;
return;
}
int m=l+(r-l)/;
p[m].tag=;
cmpNo=d,o=m;
nth_element(p+l,p+m,p+r+,cmp);
build(p[o].lc,l,m-,d^);
build(p[o].rc,m+,r,d^);
maintain(o);
}
bool all(int o){
if(p[o].mxn[]<=x.mxn[]&&p[o].mnn[]>=x.mnn[]&&p[o].mnn[]>=x.mnn[]&&p[o].mxn[]<=x.mxn[]){
return true;
}
return false;
}
bool have(int o){
if(p[o].mnn[o]<=x.mxn[]&&p[o].mxn[o]>=x.mnn[]&&p[o].mxn[]>=x.mnn[]&&p[o].mnn[]<=x.mxn[]){
return true;
}
return false;
}
void update(int o){
if(!o)return;
if(all(o)){
p[o].tag=x.tag;
p[o].val=x.tag;
return;
} pushdown(o);
int l=p[o].lc,r=p[o].rc;
if(p[o].x[]>=x.mnn[]&&p[o].x[]<=x.mxn[]&&p[o].x[]>=x.mnn[]&&p[o].x[]<=x.mxn[]){
p[o].val=x.tag;
}
if(all(l)){
p[l].tag=p[l].val=x.tag;
}else if(have(l)){
update(l);
}
if(all(r)){
p[r].tag=p[r].val=x.tag;
}else if(have(r)){
update(r);
}
}
int query(int o){
if(!o)return ;
if(p[o].u==x.u){
return p[o].val;
}
pushdown(o);
int l=p[o].lc,r=p[o].rc; if(p[l].mnn[]<=x.x[]&&p[l].mxn[]>=x.x[]&&x.x[]>=p[l].mnn[]&&x.x[]<=p[l].mxn[])
return query(l);
else
return query(r);
}
void init(){
sz=;
cnt=;
memset(head,-,sizeof(head));
}
void add_edge(int a,int b){
++sz;
to[sz]=b;
Next[sz]=head[a];
head[a]=sz;
}
void dfs(int u,int fa,int dep){
depth[u]=dep;
order[++cnt]=u;
indx[u]=cnt;
st[u]=cnt;
for(int i=head[u];i!=-;i=Next[i]){
int v=to[i];
if(v==fa)
continue;
dfs(v,u,dep+);
}
en[u]=cnt;
}
int main(){
scanf("%d",&T);
for(int kase=;kase<=T;kase++){
scanf("%d%d%d",&n,&c,&q);
init();
for(int i=;i<=n;i++){
int fa;
scanf("%d",&fa);
add_edge(fa,i);
add_edge(i,fa);
}
dfs(,-,);
for(int i=;i<=n;i++){
p[i].x[]=indx[i];
p[i].x[]=depth[i];
p[i].u=i;
p[i].val=;
p[i].tag=p[i].lc=p[i].rc=;
}
p[].mnn[]=p[].mnn[]=INF;
p[].mxn[]=p[].mxn[]=-INF;
build(root,,n,);
LL ans=;
for(int i=;i<=q;i++){
int a,l,c;
scanf("%d%d%d",&a,&l,&c);
if(c){
x.mnn[]=st[a],x.mxn[]=en[a],x.tag=c;
x.mnn[]=depth[a],x.mxn[]=depth[a]+l;
update(root);
}else{
x.u=a;
x.x[]=indx[a];
x.x[]=depth[a];
ans=(ans+(LL)i*query(root))%mod;
// printf("%d\n",query(root,0));
}
}
printf("%lld\n",ans);
}
return ;
}