【BZOJ4154】[Ipsc2015]Generating Synergy KDtree

【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<=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\n",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

 

posted @ 2017-09-17 15:30  CQzhangyu  阅读(265)  评论(0编辑  收藏  举报