4154: [Ipsc2015]Generating Synergy
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 1013 Solved: 390
[Submit][Status][Discuss]
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
Source
解题思路:kd-tree,可以以每个节点的 DFS 序作为横坐标,深度作为纵坐标,那么就可以把一棵树放在坐标系里了,一次 a 节点,距离为 l 的染色就是纵坐标从 dep[a] 到 dep[a] + l,横坐标从 dfsx[a] 到 dfsx[a] + size[a] - 1 的矩形,dep[a] 表示节点 a 的深度,dfsx[a] 指节点 a 的 DFS 序,size[a] 表示以节点 a 为根的子树大小。更新需要标记下传像线段树一样弄一个标记不断向下移即可。
#include <iostream>
#include <string.h>
#include <math.h>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int MAXN = 200050;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int DIM=2;//维度数
int nowD;//当前排序的维度
struct node{
int Min[2],Max[2];//这个点所维护的块内,离这个点最远的值和最近的值
int d[2];//这个点的坐标
int l,r;//这个块所维护的点的区间
int col;
int lazy;
friend bool operator <(const node &a,const node &b){
return a.d[nowD] < b.d[nowD];
}
}t[MAXN];
void pushup(int now) //由子节点控制范围来更新now点的控制范围
{
for(int i =0;i<DIM;i++){
if(t[now].l)
{
if(t[t[now].l].Max[i]>t[now].Max[i]) t[now].Max[i]=t[t[now].l].Max[i];
if(t[t[now].l].Min[i]<t[now].Min[i]) t[now].Min[i]=t[t[now].l].Min[i];
}
if(t[now].r)
{
if(t[t[now].r].Max[i]>t[now].Max[i]) t[now].Max[i]=t[t[now].r].Max[i];
if(t[t[now].r].Min[i]<t[now].Min[i]) t[now].Min[i]=t[t[now].r].Min[i];
}
}
}
int build(int l,int r,int D) //kd树的建立
{
int mid=(l+r)>>1;
nowD=D;
nth_element(t+l,t+mid,t+r+1);//类似快排,快排后,左边的都比mid小,右边的都比mid大,这样就可以正确的递归了
if(l!=mid) t[mid].l=build(l,mid-1,(D+1)%DIM);else t[mid].l=0;//递归
if(r!=mid) t[mid].r=build(mid+1,r,(D+1)%DIM);else t[mid].r=0;
for(int i=0;i<DIM;i++){
t[mid].Max[i]=t[mid].Min[i]=t[mid].d[i];//初始化
}
pushup(mid);//更新
return mid;
}
//检查这一块是否可能存在答案,更新用
bool check(int p,node x){
if(p==0)
return false;
if(t[p].Max[0]<x.Min[0]||t[p].Min[0]>x.Max[0]) return false;
if(t[p].Max[1]<x.Min[1]||t[p].Min[1]>x.Max[1]) return false;
return true;
}
//检查这一块是否可能存在答案, 查询用
bool check1(int p,node x){
if(p==0)
return false;
if(t[p].Max[0]<x.d[0]||t[p].Min[0]>x.d[0]) return false;
if(t[p].Max[1]<x.d[1]||t[p].Min[1]>x.d[1]) return false;
return true;
}
void pushdown(int a){
if(t[a].lazy!=-1){
t[t[a].l].lazy=t[a].lazy;
t[t[a].r].lazy=t[a].lazy;
t[a].col=t[a].lazy;
t[a].lazy=-1;
}
}
node temp;
ll query(int p)
{
pushdown(p);
if(t[p].d[0]==temp.d[0]&&t[p].d[1]==temp.d[1])//找到答案返回
return t[p].col;
if(!t[p].l&&!t[p].r)
return -1;
ll ans=-1;
if(check1(t[p].l,temp))//检查是否可能存在答案
ans = query(t[p].l);
if(ans!=-1)
return ans;
return query(t[p].r);
}
void update(int p){
//区间更新
if(t[p].Min[0]>=temp.Min[0]&&t[p].Max[0]<=temp.Max[0]&&t[p].Min[1]>=temp.Min[1]&&t[p].Max[1]<=temp.Max[1]){
t[p].lazy=temp.col;
t[p].col=temp.col;
return;
}
pushdown(p);
//单点更新
if(t[p].d[0]>=temp.Min[0]&&t[p].d[0]<=temp.Max[0]&&t[p].d[1]>=temp.Min[1]&&t[p].d[1]<=temp.Max[1]){
t[p].col=temp.col;
}
if(check(t[p].l,temp))
update(t[p].l);
if(check(t[p].r,temp))
update(t[p].r);
}
vector<int> G[MAXN];
int dep[MAXN];
int siz[MAXN];
int dfn[MAXN];
int clo=0;
void dfs(int u,int d){
siz[u]=1;
dep[u]=d;
dfn[u]=clo++;
for(int i=0;i<G[u].size();i++)
{
dfs(G[u][i],d+1);
siz[u]+=siz[G[u][i]];
}
}
int main()
{
int T;
scanf("%d",&T);
int N,C,Q;
while(T--){
clo=1;
scanf("%d%d%d",&N,&C,&Q);
int tmp;
for(int i=2;i<=N;i++){
scanf("%d",&tmp);
G[tmp].push_back(i);
}
dfs(1,1);
for(int i=1;i<=N;i++){
t[i].d[0]=dfn[i];
t[i].d[1]=dep[i];
t[i].lazy=-1;
t[i].col=1;
}
int rt=build(1,N,0);
ll ans=0;
int a,one,c;
for(int i=1;i<=Q;i++){
scanf("%d%d%d",&a,&one,&c);
if(c==0){
temp.d[0]=dfn[a];
temp.d[1]=dep[a];
ll yi=query(rt);
ans=(ans+(yi*i)%ll(1e9+7))%ll(1e9+7);
}
else{
temp.Min[0]=dfn[a];
temp.Max[0]=dfn[a]+siz[a]-1;
temp.Min[1]=dep[a];
temp.Max[1]=dep[a]+one;
temp.col=c;
update(rt);
}
}
printf("%lld\n",ans);
for(int i=0;i<=N;i++)
G[i].clear();
}
return 0;
}