【bzoj 4154】[Ipsc2015]Generating Synergy

题目

大概已经掌握熟练码出\(kdt\)的技能了

发现距离子树根节点\(x\)不超过\(l\)的点可以用两种方式来限制,首先\(dfs\)序在\([dfn_x,dfn_x+sum_x)\)中,深度自然也要满足\([deep_x,deep_x+l]\)

发现这变成了对一个子矩形染色同时询问单点颜色的题目

我们直接\(kdt\)打标机就好了

需要注意的一点是,仅对\(kdt\)中子树的根进行的修改不打标机

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int mod=1e9+7;
const int maxn=1e5+5;
struct E{int v,nxt;}e[maxn];
int head[maxn],deep[maxn],sum[maxn],dfn[maxn];
struct Point{int x[2];}p[maxn],t;
int n,num,cnt,__,op,T,C,m;
int x1,x2,y1,y2;
int l[maxn],r[maxn],tag[maxn],col[maxn],mx[maxn][2],mi[maxn][2],id[maxn];
inline void add(int x,int y) {
	e[++num].v=y;e[num].nxt=head[x];head[x]=num;
}
inline int cmp(Point A,Point B) {
	if(A.x[op]==B.x[op]) return A.x[op^1]<B.x[op^1];
	return A.x[op]<B.x[op];
}
void dfs(int x) {
	dfn[x]=++__;sum[x]=1;
	for(re int i=head[x];i;i=e[i].nxt) {
		deep[e[i].v]=deep[x]+1;
		dfs(e[i].v);
		sum[x]+=sum[e[i].v];
	}
}
inline void pushup(int k) {
	mx[k][0]=mi[k][0]=p[id[k]].x[0];
	mx[k][1]=mi[k][1]=p[id[k]].x[1];
	for(re int i=0;i<2;i++) {
		if(l[k]) mx[k][i]=max(mx[k][i],mx[l[k]][i]),
				 mi[k][i]=min(mi[k][i],mi[l[k]][i]);
		if(r[k]) mx[k][i]=max(mx[k][i],mx[r[k]][i]),
				 mi[k][i]=min(mi[k][i],mi[r[k]][i]);
	}
}
inline void pushdown(int k) {
	if(tag[k]==-1) return;
	tag[r[k]]=tag[l[k]]=tag[k];
	col[l[k]]=col[r[k]]=tag[k];
	tag[k]=-1;
}
int build(int x,int y,int o) {
	if(x>y) return 0;
	int mid=x+y>>1,k=++cnt;col[k]=1;
	op=o;std::nth_element(p+x,p+mid,p+y+1,cmp);id[k]=mid;
	l[k]=build(x,mid-1,o^1);r[k]=build(mid+1,y,o^1);
	pushup(k);return k;
}
int ask(int k,int o) {
	if(t.x[0]==p[id[k]].x[0]&&t.x[1]==p[id[k]].x[1]) 
		return col[k];
	pushdown(k);
	if(t.x[o]==p[id[k]].x[o]) {
		if(t.x[o^1]<p[id[k]].x[o^1]) return ask(l[k],o^1);
		return ask(r[k],o^1);
	}
	if(t.x[o]<p[id[k]].x[o]) return ask(l[k],o^1);
	if(t.x[o]>p[id[k]].x[o]) return ask(r[k],o^1);
}
inline int out(int k) {
	return (mx[k][0]<x1||mi[k][0]>x2||mx[k][1]<y1||mi[k][1]>y2);
}
inline int in(int k) {
	return (mi[k][0]>=x1&&mx[k][0]<=x2&&mi[k][1]>=y1&&mx[k][1]<=y2);
}
inline int chk(Point a) {
	return (a.x[0]>=x1&&a.x[0]<=x2&&a.x[1]>=y1&&a.x[1]<=y2);
}
void change(int k,int c) {
	if(!k||out(k)) return;
	pushdown(k);
	if(in(k)) {col[k]=c,tag[k]=c;return;}
	if(chk(p[id[k]])) col[k]=c;
	change(l[k],c);change(r[k],c);
}
int main() {
	T=read();
	while(T--) {
		n=read(),C=read(),m=read();num=0;cnt=0;
		memset(head,0,sizeof(head));
		memset(mx,0,sizeof(mx));
		memset(mi,0,sizeof(mi));
		memset(tag,-1,sizeof(tag));
		for(re int x,i=2;i<=n;i++)
			x=read(),add(x,i);
		deep[1]=1,dfs(1);
		for(re int i=1;i<=n;i++)
			p[i].x[0]=dfn[i],p[i].x[1]=deep[i];
		build(1,n,0);int ans=0;
		for(re int x,c,l,i=1;i<=m;i++) {
			x=read(),l=read(),c=read();
			if(!c) {
				t.x[0]=dfn[x];
				t.x[1]=deep[x];
				ans=(ans+1ll*i*ask(1,0)%mod)%mod;
				continue;
			}
			x1=dfn[x],x2=dfn[x]+sum[x]-1;
			y1=deep[x],y2=deep[x]+l;
			change(1,c);
		}
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2019-04-23 17:02  asuldb  阅读(268)  评论(0编辑  收藏  举报