BZOJ4154:Generating Synergy (KDtree)

传送门

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

题解:KDtree
看完这道题题解,我只想说:还有这种操作???

想了半天的点分治,后来发现看错题了,原来只有子节点。。。

KDtree:
首先将每个点的横坐标看做dfs序,那么修改在一个区间内进行,由于这些点只有部分点会被修改,而修改的点的 dep 又是一段连续的区间,就像是二维点对中的一个矩形,那么直接kdtree就好了,时间复杂度 O(nn) ,当然这个是最坏复杂度。实测跑得还是挺快的。(听说树套树也能做,然而我并不会。。)

#include<bits/stdc++.h>
using namespace std;
struct IO{
    streambuf *ib,*ob;
    inline void init(){
        ios::sync_with_stdio(false);
        cin.tie(NULL);cout.tie(NULL);
        ib=cin.rdbuf();ob=cout.rdbuf();
    }
    inline int read(){
        char ch=ib->sbumpc();int i=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=ib->sbumpc();}
        while(isdigit(ch)){i=(i+(i<<2)<<1)+ch-'0';ch=ib->sbumpc();}
        return i*f;
    }
    inline void W(long long x){
        static int buf[50];
        if(!x){ob->sputc('0');ob->sputc('\n');return;}
        if(x<0){ob->sputc('-');x=-x;}
        while(x){buf[++buf[0]]=x%10;x/=10;}
        while(buf[0])ob->sputc(buf[buf[0]--]+'0');
        ob->sputc('\n');
    }
}io;

const int Maxn=1e5+50;
const int Mod=1e9+7;
int n,c,q,ans,dep[Maxn],in[Maxn],out[Maxn],ind;
struct point{
    int x[2],id;
    point(int Id=0,int x0=0,int x1=0){
        x[0]=x0;x[1]=x1;id=Id;
    }
}PointPool[Maxn],*pointpool=PointPool;
inline point newpoint(int id,int x,int y){
    ++pointpool;
    pointpool->x[0]=x;pointpool->x[1]=y;pointpool->id=id;
    return *pointpool;
}
inline bool cmpx(const point &a,const point &b){return a.x[0]<b.x[0]||(a.x[0]==b.x[0]&&a.id<b.id);}
inline bool cmpy(const point &a,const point &b){return a.x[1]<b.x[1]||(a.x[1]==b.x[1]&&a.id<b.id);}
struct node{
    node *lc,*rc;
    int mnx[2],mxx[2];
    point p;int c,tag;
    inline void upt();
    inline void addtag(int col){
        c=col;tag=col;
    }
    inline void pushdown();
}NodePool[Maxn],*nodepool=NodePool,*null=NodePool;
inline node* newnode(int id,int x,int y){
    ++nodepool;
    nodepool->p=newpoint(id,x,y);
    nodepool->lc=nodepool->rc=null;
    nodepool->tag=-1;nodepool->c=1;
    nodepool->mnx[0]=nodepool->mxx[0]=x;
    nodepool->mnx[1]=nodepool->mxx[1]=y;
    return nodepool;
}
inline void node::pushdown(){
    if(tag==-1)return;
    if(lc!=null)lc->addtag(tag);
    if(rc!=null)rc->addtag(tag);
    tag=-1;
}
inline void node::upt(){
    for(int i=0;i<2;i++){
        mnx[i]=mxx[i]=p.x[i];
        if(lc!=null)mnx[i]=min(mnx[i],lc->mnx[i]),mxx[i]=max(mxx[i],lc->mxx[i]);
        if(rc!=null)mnx[i]=min(mnx[i],rc->mnx[i]),mxx[i]=max(mxx[i],rc->mxx[i]);
    }
}
struct kd_tree{
    node *rt;
    point que[Maxn],t;
    int tail;
    inline void init(){
        rt=null;
        tail=0;
    }
    inline void build(node*& now,int l,int r,int dim){
        if(l==r){
            now=newnode(que[l].id,que[l].x[0],que[l].x[1]);
            return;
        }
        int mid=(l+r)>>1;
        dim?(nth_element(que+l,que+mid,que+r+1,cmpy)):(nth_element(que+l,que+mid,que+r+1,cmpx));
        now=newnode(que[mid].id,que[mid].x[0],que[mid].x[1]);
        if(l<mid)build(now->lc,l,mid-1,dim^1);
        if(r>mid)build(now->rc,mid+1,r,dim^1);
        now->upt();
    }
    inline bool In(node *now,int x0,int x1,int y0,int y1){
        return now->mnx[0]>=x0&&now->mxx[0]<=x1&&now->mnx[1]>=y0&&now->mxx[1]<=y1;
    }
    inline bool insertline(int x0,int x1,int y0,int y1){
        return (x0>=y0&&x0<=y1)||(x1>=y0&&x1<=y1)||(y0>=x0&&y0<=x1);
    }
    inline bool insert(node *now,int x0,int x1,int y0,int y1){
        return insertline(now->mnx[0],now->mxx[0],x0,x1)&&insertline(now->mnx[1],now->mxx[1],y0,y1);
    }
    inline void modify(node *now,int x0,int x1,int y0,int y1,int c){
        if(In(now,x0,x1,y0,y1)){
            now->addtag(c);
            return;
        }
        now->pushdown();
        if(now->p.x[0]>=x0&&now->p.x[0]<=x1&&now->p.x[1]>=y0&&now->p.x[1]<=y1)now->c=c;
        if(now->lc!=null&&insert(now->lc,x0,x1,y0,y1))modify(now->lc,x0,x1,y0,y1,c);
        if(now->rc!=null&&insert(now->rc,x0,x1,y0,y1))modify(now->rc,x0,x1,y0,y1,c);
    }
    inline int query(node *now,int id,int dim){
        if(id==now->p.id)return now->c;
        now->pushdown();
        if(now->lc!=null&&(dim?cmpy(t,now->p):cmpx(t,now->p)))return query(now->lc,id,dim^1);
        else return query(now->rc,id,dim^1);
    }
}kdtree;

vector<int>edge[Maxn];
inline void dfs(int now,int f){
    dep[now]=dep[f]+1;in[now]=++ind;kdtree.que[++kdtree.tail]=point(now,in[now],dep[now]);
    for(int e=edge[now].size()-1;e>=0;e--){
        int v=edge[now][e];
        if(v==f)continue;
        dfs(v,now);
    }
    out[now]=ind;
}

int main(){
    io.init();
    int T=io.read();
    while(T--){
        pointpool=PointPool,nodepool=NodePool,kdtree.init();
        n=io.read(),c=io.read(),q=io.read(),ans=ind=0;
        for(int i=1;i<=n;i++)edge[i].clear();
        for(int i=2;i<=n;i++){
            edge[io.read()].push_back(i);
        }
        dfs(1,0);
        kdtree.build(kdtree.rt,1,n,0);
        for(int i=1;i<=q;i++){
            int x=io.read(),l=io.read(),c=io.read();
            if(c)kdtree.modify(kdtree.rt,in[x],out[x],dep[x],dep[x]+l,c);
            else kdtree.t=point(x,in[x],dep[x]),(ans+=1ll*i*kdtree.query(kdtree.rt,x,0)%Mod)%=Mod;
        }
        io.W(ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值