您的位置:首页 > 其它

[Ipsc2015]Generating Synergy K-D tree

2017-12-02 09:57 225 查看

NKOJ 4345 Generating Synergy

问题描述

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

输入格式

第一行一个数T,表示数据组数

接下来每组数据的第一行三个数n,c,q表示结点个数,颜色数和操作数

接下来一行n-1个数描述2..n的父节点

接下来q行每行三个数a,l,c

若c为0,表示询问a的颜色

否则将距离a不超过l的a的子节点染成c

输出格式

设当前是第i个操作,y_i为本次询问的答案(若本次操作是一个修改则y_i为0),令z_i=i*y_i,请输出z_1+z_2+…+z_q模10^9+7

样例输入

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

样例输出

32

数据范围

对于100%的数据T<=6,n,m,c<=10^5,

1<=a<=n,0<=l<=n,0<=c<=c

单点查询不是问题,对于多点修改,显然想把它转换为区间修改,这样才能通过打标记保证时间复杂度。

首先容易想到处理“距离不超过l”就用深度就可以搞定了。那么还需要“在子树内”的条件。用DFS序就可以方便地知道一个节点管辖的范围。

因此,如果把每个树上的节点对应为二维空间里的点(In[x],dep[x]),每次修改的就是横坐标在[In[x],Out[x]],纵坐标在[dep[x],dep[x]+l]的点,是一个矩形区间。可
4000
以用树套树,但是K-D tree更易于实现。

注意修改操作与线段树不同,与平衡树相似:节点本身就代表了一个点。而线段树则是只有底层代表了原来的点。

#include<stdio.h>
#include<algorithm>
#include<cstring>
#define MAXN 100005
#define MAXM 200005
#define ll long long
#define Max(x,y) ((x>y)?(x):(y))
#define Min(x,y) ((x<y)?(x):(y))
using namespace std;

const ll mod=1e9+7;

int N,C,Q,Hash[MAXN];

int D;

struct node{
int d[2],x[2],y[2],son[2],c,id,lazy;
bool operator<(const node &x)const{return d[D]<x.d[D];}
}A[MAXN],T[MAXN];

int en[MAXM],nex[MAXM],las[MAXN],Tot;
void Add(int x,int y)
{
en[++Tot]=y;
nex[Tot]=las[x];
las[x]=Tot;
}

int VT,In[MAXN],Out[MAXN],dep[MAXN];
void DFS(int x,int f)
{
int i,y;

In[x]=++VT;dep[x]=dep[f]+1;
for(i=las[x];i;i=nex[i])
{
y=en[i];
if(y!=f)DFS(y,x);
}
Out[x]=VT;
}

void Update(int p,int s)
{
T[p].x[0]=Min(T[p].x[0],T[s].x[0]);
T[p].x[1]=Max(T[p].x[1],T[s].x[1]);
T[p].y[0]=Min(T[p].y[0],T[s].y[0]);
T[p].y[1]=Max(T[p].y[1],T[s].y[1]);
}

void Putdown(int p)
{
int ls=T[p].son[0],rs=T[p].son[1];
if(ls)T[ls].c=T[ls].lazy=T[p].lazy;
if(rs)T[rs].c=T[rs].lazy=T[p].lazy;
T[p].lazy=0;
}

int tot;
int Build(int l,int r,int d)
{
D=d;
int p=++tot,mid=l+r>>1;
nth_element(A+l,A+mid,A+r+1);
T[p].d[0]=T[p].x[0]=T[p].x[1]=A[mid].d[0];
T[p].d[1]=T[p].y[0]=T[p].y[1]=A[mid].d[1];
T[p].c=1;T[p].lazy=0;
if(l<mid)T[p].son[0]=Build(l,mid-1,d^1),Update(p,T[p].son[0]);else T[p].son[0]=0;
if(r>mid)T[p].son[1]=Build(mid+1,r,d^1),Update(p,T[p].son[1]);else T[p].son[1]=0;
return p;
}

int check(int p,int l,int r,int u,int d)
{
if(T[p].x[0]>=l&&T[p].x[1]<=r&&T[p].y[0]>=d&&T[p].y[1]<=u)return 2;
if(T[p].x[0]>r||T[p].x[1]<l||T[p].y[0]>u||T[p].y[1]<d)return 0;
return 1;
}

void Modify(int p,int l,int r,int u,int d,int k)
{
if(T[p].lazy)Putdown(p);
int ck=check(p,l,r,u,d);
if(ck==2){T[p].lazy=k;T[p].c=k;return;}
if(ck==0)return;
if(T[p].d[0]>=l&&T[p].d[0]<=r&&T[p].d[1]<=u&&T[p].d[1]>=d)T[p].c=k;
if(T[p].son[0])Modify(T[p].son[0],l,r,u,d,k);
if(T[p].son[1])Modify(T[p].son[1],l,r,u,d,k);
}

int Ans;
void Query(int p,int x,int y,int d)
{
if(Ans)return;
if(T[p].lazy)Putdown(p);
if(T[p].d[0]==x&&T[p].d[1]==y){Ans=T[p].c;return;}
int ls=T[p].son[0],rs=T[p].son[1];
if(d)
{
if(ls&&T[ls].x[0]<=x&&T[ls].x[1]>=x)Query(ls,x,y,d^1);
if(rs&&T[rs].x[0]<=x&&T[rs].x[1]>=x)Query(rs,x,y,d^1);
}
else
{
if(ls&&T[ls].y[0]<=y&&T[ls].y[1]>=y)Query(ls,x,y,d^1);
if(rs&&T[rs].y[0]<=y&&T[rs].y[1]>=y)Query(rs,x,y,d^1);
}
}

ll TotAns;
void Clear()
{
VT=0;
memset(las,0,sizeof(las));Tot=0;
tot=0;
TotAns=0;
}

int main()
{
int t;

scanf("%d",&t);
while(t--)
{
Clear();

int i,x,y,op;

scanf("%d%d%d",&N,&C,&Q);
for(i=2;i<=N;i++)scanf("%d",&x),Add(x,i);

DFS(1,0);

for(i=1;i<=N;i++)A[i].d[0]=In[i],A[i].d[1]=dep[i];

Build(1,N,0);

for(i=1;i<=Q;i++)
{
scanf("%d%d%d",&x,&y,&op);
if(op==0)
{
Ans=0;
Query(1,In[x],dep[x],0);
TotAns=(TotAns+1ll*Ans*i)%mod;
}
else Modify(1,In[x],Out[x],dep[x]+y,dep[x],op);
}

printf("%lld\n",TotAns);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: