[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
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<\leqslant6,n,m,C\leqslant10^5\),
\(1\leqslant a\leqslant n,0\leqslant l\leqslant n,0\leqslant c\leqslant C\)
对每个点求出dfs序\(L_i,R_i\),和深度\(d_i\),然后每个点映射为平面上的\((L_i,d_i)\)的一个点,每次修改相当于对\(L_i\leqslant L_x\leqslant R_i,d_i\leqslant d_x\leqslant d_i+l\)的\(x\)染色,这个可以转化为平面上的矩阵操作
我们建立一棵KD-Tree,支持打区间覆盖标记即可
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
int x=0,f=1; char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline int read(){
int x=0,f=1; char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
const int N=1e5,Mod=1e9+7;
int pre[(N<<1)+10],now[N+10],child[(N<<1)+10];
int deep[N+10],dfn[N+10],size[N+10],pos[N+10];//pos记录i在KD-Tree中的编号
int n,c,q,Time,tot,T;
void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
void insert(int x,int y){join(x,y),join(y,x);}
void dfs(int x,int fa){
deep[x]=deep[fa]+1,dfn[x]=++Time,size[x]=1;
for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
if (son==fa) continue;
dfs(son,x);
size[x]+=size[son];
}
}
struct S1{
#define ls(x) tree[x].ls
#define rs(x) tree[x].rs
struct node{
int v[2],Max[2],Min[2];
int Lazy,val,ls,rs,ID,fa;
bool operator <(const node &tis)const{return v[T]<tis.v[T];}
}tree[N+10];
int root,L[2],R[2];
void Add(int *a,int v){a[0]=a[1]=v;}
int build(int l,int r,int type,int fa){
T=type;
int mid=(l+r)>>1,p=mid;
nth_element(tree+l,tree+mid,tree+r+1);
tree[p].val=1,tree[p].Lazy=0,tree[p].fa=fa;
tree[p].ls=tree[p].rs=0;
pos[tree[p].ID]=p;
if (l<mid) ls(p)=build(l,mid-1,type^1,p);
if (r>mid) rs(p)=build(mid+1,r,type^1,p);
tree[p].Min[0]=min(tree[p].v[0],min(tree[ls(p)].Min[0],tree[rs(p)].Min[0]));
tree[p].Min[1]=min(tree[p].v[1],min(tree[ls(p)].Min[1],tree[rs(p)].Min[1]));
tree[p].Max[0]=max(tree[p].v[0],max(tree[ls(p)].Max[0],tree[rs(p)].Max[0]));
tree[p].Max[1]=max(tree[p].v[1],max(tree[ls(p)].Max[1],tree[rs(p)].Max[1]));
return p;
}
void init(){
Add(tree[0].Max,-inf),Add(tree[0].Min,inf);
for (int i=1;i<=n;i++) tree[i].v[0]=dfn[i],tree[i].v[1]=deep[i],tree[i].ID=i;
root=build(1,n,0,0);
}
void Add_tag(int p,int v){
tree[p].val=v;
tree[p].Lazy=v;
}
void pushdown(int p){
if (!tree[p].Lazy) return;
Add_tag(ls(p),tree[p].Lazy);
Add_tag(rs(p),tree[p].Lazy);
tree[p].Lazy=0;
}
void Modify(int p,int v){
bool flag=1;
for (int i=0;i<2;i++) if (R[i]<tree[p].Min[i]||L[i]>tree[p].Max[i]) return;
for (int i=0;i<2;i++){
if (L[i]>tree[p].Min[i]||R[i]<tree[p].Max[i]){
flag=0;
break;
}
}
if (flag){
Add_tag(p,v);
return;
}flag=1;
pushdown(p);
for (int i=0;i<2;i++){
if (tree[p].v[i]<L[i]||R[i]<tree[p].v[i]){
flag=0;
break;
}
}
if (flag) tree[p].val=v;
Modify(ls(p),v);
Modify(rs(p),v);
}
void Modify(int l1,int r1,int l2,int r2,int v){
L[0]=l1,L[1]=l2,R[0]=r1,R[1]=r2;
Modify(root,v);
}
int Query(int p){//找到其到root的链,一路pushdown即可
static int stack[N+10]; int top=0,x=p;
stack[++top]=p;
while (tree[p].fa) stack[++top]=tree[p].fa,p=tree[p].fa;
for (int i=top;i;i--) pushdown(stack[i]);
return tree[x].val;
}
#undef ls
#undef rs
}KDT;//KD-Tree
int main(){
for (int T=read();T;T--){
n=read(),c=read(),q=read();
int res=0; Time=0,tot=0;
memset(now,0,sizeof(now));
for (int i=2;i<=n;i++) insert(read(),i);
dfs(1,0),KDT.init();
for (int i=1;i<=q;i++){
int a=read(),l=read(),c=read();
if (c) KDT.Modify(dfn[a],dfn[a]+size[a]-1,deep[a],deep[a]+l,c);
else res=(1ll*i*KDT.Query(pos[a])+res)%Mod;
}
printf("%d\n",res);
}
return 0;
}