[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;
}
posted @ 2019-01-14 21:13  Wolfycz  阅读(325)  评论(0编辑  收藏  举报