BZOJ - 4154 Generating Synergy (KDTree 区间更新)

版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/82773146

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

[Submit][Status][Discuss]



解题思路: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;
}










猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/82773146