BZOJ 4154(Generating Synergy-kd-tree代替树套树)

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

首先把一个点的dfs序值和深度变成2维平面的点 (In i ,d i )(Out i ,d i ) 
于是变成矩阵修改与单点求值

显然可以树套树,kd-tree,

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (1000000000)
#define F (1000000007)
#define MAXN (200000+10)
#define fac 0.65
typedef long long ll;

int cmp_d=0;
class node
{
public:
    int x[2];
    int l,r,minv[2],maxv[2];
    int w,siz,setv,id,f;
    node(){}
    node(int a,int b,int _w=0,int _id=0){l=r=f=0; setv=0; siz=1; w=_w; id=_id; x[0]=a,x[1]=b; Rep(i,2) minv[i]=maxv[i]=x[i];}
    int& operator[](int i){return x[i]; } 
};

int cmp(node a,node b){return a[cmp_d]<b[cmp_d];    }

int p;
char c;
int read()
{
    while (c=getchar(),!isdigit(c));
    p=c-'0';
    while (isdigit(c=getchar())) p=p*10+c-'0'; return p;
}

int id[MAXN];

class KD_Tree
{
public: 
    node a[MAXN];

    void pushdown(node &o) {
        if (o.setv) {
            if (o.l) a[o.l].setv=a[o.l].w=o.setv;
            if (o.r) a[o.r].setv=a[o.r].w=o.setv;
            o.setv=0;
        }
    }
    void update(node& o)
    {
        if (o.l)
        {
            node p=a[o.l];
            Rep(i,2) o.minv[i]=min(o.minv[i],p.minv[i]);
            Rep(i,2) o.maxv[i]=max(o.maxv[i],p.maxv[i]);    
        }
        if (o.r)
        {
            node p=a[o.r];
            Rep(i,2) o.minv[i]=min(o.minv[i],p.minv[i]);
            Rep(i,2) o.maxv[i]=max(o.maxv[i],p.maxv[i]);    
        }

    }
    int build(int L,int R,int nowd,node *a)
    {
        int m=(L+R)>>1;

        cmp_d=nowd;
        nth_element(a+L+1,a+m+1,a+R+1,cmp);

        if (L^m) a[m].l=build(L,m-1,nowd^1,a),a[a[m].l].f=m;
        if (R^m) a[m].r=build(m+1,R,nowd^1,a),a[a[m].r].f=m;
        update(a[m]);
        return m;

    } 


    int root;
    void _build(int L,int R,int nowd) //1-n的节点 至少为1 
    {
        root=build(L,R,nowd,a);
    }

    int query(int o,int k,int nowd)
    {
        if (!o) return 0;
        if (a[k].x[0]==a[o].x[0] && a[k].x[1]==a[o].x[1] ) return a[o].w;
        int p=a[o].x[nowd];
        int p2=a[k].x[nowd];
        pushdown(a[o]); 
        int _ans=0;
        if (p2<=p) 
        {
            _ans=max(_ans,query(a[o].l,k,nowd^1));
        }
        if (p2>=p)
        {
            _ans=max(_ans,query(a[o].r,k,nowd^1));
        }   
        return _ans;

    }
    int _query(int k)
    {
        int ans=a[k].w;
        while (k) {
            if (a[k].setv) ans=a[k].setv;
            k=a[k].f;
        }
        return ans; 
    }



    void set(int o)
    {
        if (o==0) return;
        pushdown(a[o]);
        if (_x1<=a[o].minv[0] && a[o].maxv[0]<=_x2 && _y1<=a[o].minv[1] && a[o].maxv[1]<=_y2 ) {
            a[o].setv=a[o].w=_v;return;
        }       

        if (_x1<=a[o].x[0] && a[o].x[0]<=_x2 && _y1<=a[o].x[1] && a[o].x[1]<=_y2 ) {
            a[o].w=_v;
        }   

        if (a[o].l) {
            int p=a[o].l;
            if (a[p].minv[0]<=_x2 && _x1<=a[p].maxv[0] && a[p].minv[1]<=_y2 && _y1<=a[p].maxv[1] ) 
                set(p);
        }
        if (a[o].r) {
            int p=a[o].r;
            if (a[p].minv[0]<=_x2 && _x1<=a[p].maxv[0] && a[p].minv[1]<=_y2 && _y1<=a[p].maxv[1] ) 
                set(p);
        }


    }

    int _v;
    void _set(int x1,int y1,int x2,int y2,int v)
    {
        _x1=x1;_y1=y1;_x2=x2;_y2=y2;_v=v;
        set(root);
    }

    int _x1,_y1,_x2,_y2;

}S;

int n,C,q;
int Pre[MAXN],Next[MAXN],edge[MAXN],siz=1;
void addedge(int u,int v){
    edge[++siz]=v;
    Next[siz]=Pre[u];
    Pre[u]=siz;
}

int fa[MAXN],d[MAXN],Time,In[MAXN],Out[MAXN];
void dfs(int x,int dep)
{
    In[x]=++Time;

    d[x]=dep;
    Forp(x)
    {
        int v=edge[p];
        dfs(v,dep+1);
    }
    Out[x]=++Time;
}

int main()
{
//  freopen("bzoj4154.in","r",stdin);
    int T;cin>>T;
    while(T--) {
        ll ans=0;
        MEM(Pre) siz=1;     

        cin>>n>>C>>q;
        Fork(i,2,n) fa[i]=read(),addedge(fa[i],i);
        Time=0;
        dfs(1,1);


        For(i,n) S.a[i]=node(In[i],d[i],1,i);
        S._build(1,n,0);
        For(i,n) id[S.a[i].id]=i;

        For(i,q) {
            int a,l,co;
            a=read(),l=read(),co=read();
            if (co==0) {
                ans=(ans+1LL*i*S._query(id[a])%F)%F;
            } else 
            {
                S._set(In[a],d[a],Out[a],d[a]+l,co);
            }

        } 

        cout<<ans<<endl; 

    }


    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值