CF1017G 【The Tree】

Linkernode

作法:樹鏈剖分+線段樹c++

首先\(O(n^2)\)的暴力仍是挺好想的,就很少闡述了。ui

而後看沒有2操做的該怎麼寫。spa

當沒有2操做的時候,咱們能夠經過一種特殊的形式來記錄點的染色:經過給這個點加權值。debug

假設x是y的祖先,若x能夠影響到y的話,不難發現,須要知足的性質就是 \(x\to y\ \text{這一段路上的總權值}>=dep[x]-dep[y]+1\)code

記錄這一段路上的總權值爲\(dis\),移項獲得 \(dis+dep[x]>=dep[y]+1\)get

利用線段樹維護\(dis+dep[x]\),而後對於向上跳的過程直接樹鏈剖分向上跳。it

也就是說經過樹鏈剖分+線段樹就能寫出來。這裏代碼就不放出來了。class

再看若是有了2操做咱們該如何寫。bug

首先把這一整課子樹清空是確定要的。

而後就看若是祖先的\(dis\)的影響到了下面的節點該如何操做。

再來看看剛剛的式子 : \(dis+dep[x]>=dep[y]+1\)

咱們發現能夠找到x的祖先的\(dis+dep\)最大值(其實就是再往上跳一遍),也會影響到他的子樹(雖說子樹的每一個點的\(dis+dep\)已經清零了,可是仍是能夠從上面轉移下來)

因而咱們找到這個值之後,再讓x的權值減去它就行了(至關於差分)

//代碼很醜,勿噴
#include<bits/stdc++.h>
#define re register
#define rep(i,a,b) for(re int i=a,i##end=b; i<=i##end; i++)
#define drep(i,a,b) for(re int i=a,i##end=b; i>=i##end; i--)
#define repp(i,a,b) for(re int i=a,i##end=b; i<i##end; i++)
#define drepp(i,a,b) for(re int i=a,i##end=b; i>i##end; i--)
#define Erep(i,x) for(re int i=head[x]; i; i=Edge[i].nxt)
#define lowbit(x) ((x)&-(x))
#define debug(x) cerr<<#x<<" = "<<x<<endl
#define ms(x,a) memset(x,a,sizeof x)
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define fi first
#define se second
#define coint const int
#define coll const ll
#define CM cerr<<(&S2-&S1)/1024./1024.<<"MB"<<endl
typedef long long ll;
using namespace std;
template<class T>inline T rd(){
    static char ch;static bool neg;static T x;
    for(ch=0, neg=0; ch>'9'||ch<'0'; neg|=(ch=='-'),ch=getchar());
    for(x=0; ch>='0'&&ch<='9'; x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar());
    return neg?-x:x;
}
template<class T>inline T Max(const T &x, const T &y) { return x>y?x:y; }
template<class T>inline T Min(const T &x, const T &y) { return x<y?x:y; }

coint N=100000+5,M=200000+5;
struct edge{
    int to,nxt;
}Edge[N<<1];
int head[N],tcnt;
inline void AddEdge(coint u, coint v){
    Edge[++tcnt]=(edge)<%v,head[u]%>;
    head[u]=tcnt; return;
}

struct Ask{
    int opt,x;
    inline void read() { opt=rd<int>(); x=rd<int>(); return; }
}ask[M];

int n,m;

int dep[N],f[N],sz[N],son[N],top[N],L[N],R[N],ID[N],dfn;

void pre_dfs(coint x, coint fa){
    int &SZ=sz[x],&SON=son[x]; SZ=1;
    Erep(i,x){
        int y=Edge[i].to;
        if(y==fa) continue;
        dep[y]=dep[x]+1; f[y]=x;
        pre_dfs(y,x);
        SZ+=sz[y];
        SON=(sz[SON]<sz[y]?y:SON);
    }
    return;
}

void dfs_top(coint x, coint fa, coint tp){
    top[x]=tp; L[x]=++dfn; ID[dfn]=x;
    coint &SON=son[x];
    if(SON) dfs_top(SON,x,tp);
    Erep(i,x){
        int y=Edge[i].to;
        if(y==fa || y==SON) continue;
        dfs_top(y,x,y);
    } R[x]=dfn;
    return;
}

struct node{
    int sum,mx;
    friend node operator + (const node &x, const node &y){
        return (node)<%x.sum+y.sum,Max(x.mx+y.sum,y.mx)%>;
    }
};

struct Segment_Tree{
    node sum[N<<2];
    int lazy[N<<2];
    inline void Up(coint p){
        coint ls=p<<1,rs=ls|1;
        sum[p]=sum[ls]+sum[rs];
        return;
    }
    inline void Down(coint p){
        int &x=lazy[p];
        if(!x) return;
        coint ls=p<<1,rs=ls|1;
        lazy[ls]=lazy[rs]=1;
        sum[ls]=sum[rs]=(node)<%0,0%>;
        x=0; return;
    }
    void Build(coint p, coint l, coint r){
        sum[p]=(node)<%0,0%>; lazy[p]=0;
        if(l==r) return;
        coint mid=(l+r)>>1,ls=p<<1,rs=ls|1;
        Build(ls,l,mid); Build(rs,mid+1,r);
        return;
    }
    void Upd1(coint p, coint l, coint r, coint L, coint R){
        if(l==L && r==R){
            sum[p]=(node)<%0,0%>;
            lazy[p]=1;
            return;
        }
        Down(p);
        coint mid=(l+r)>>1,ls=p<<1,rs=ls|1;
        if(R<=mid) Upd1(ls,l,mid,L,R);
        else if(L>mid) Upd1(rs,mid+1,r,L,R);
        else Upd1(ls,l,mid,L,mid),Upd1(rs,mid+1,r,mid+1,R);
        Up(p); return;
    }
    void Upd2(coint p, coint l, coint r, coint x, coint val){
        if(l==r){
            sum[p]=(node)<%val,dep[ID[l]]+val%>;
            return;
        }
        Down(p);
        coint mid=(l+r)>>1,ls=p<<1,rs=ls|1;
        if(x<=mid) Upd2(ls,l,mid,x,val);
        else Upd2(rs,mid+1,r,x,val);
        Up(p); return;
    }
    node Que(coint p, coint l, coint r, coint L, coint R){
        if(l==L && r==R) return sum[p];
        Down(p);
        coint mid=(l+r)>>1,ls=p<<1,rs=ls|1;
        if(R<=mid) return Que(ls,l,mid,L,R);
        if(L>mid) return Que(rs,mid+1,r,L,R);
        return Que(ls,l,mid,L,mid)+Que(rs,mid+1,r,mid+1,R);
    }
}sgtr;

inline int Get_Max(int x){
    node res=(node)<%0,0%>;
    int tpx=top[x];
    while(x){
        res=sgtr.Que(1,1,n,L[tpx],L[x])+res;
        x=f[tpx]; tpx=top[x];
    }
    return res.mx;
}

inline void solve(){
    pre_dfs(1,0); dfs_top(1,0,1);
    rep(i,1,m){
        coint opt=(ask[i].opt),x=ask[i].x;
        switch(opt){
            case 1:{
                sgtr.Upd2(1,1,n,L[x],sgtr.Que(1,1,n,L[x],L[x]).sum+1);
                break;
            }
            case 2:{
                sgtr.Upd1(1,1,n,L[x],R[x]);
                int tmp=Get_Max(x);
                if(tmp>=dep[x]+1) sgtr.Upd2(1,1,n,L[x],dep[x]-tmp);
                break;
            }
            default:{
                puts(Get_Max(x)>=dep[x]+1?"black":"white");
                break;
            }
        }
    }
    return;
}


int main(){
    n=rd<int>(),m=rd<int>();
    rep(i,2,n){
        int x=rd<int>();
        AddEdge(x,i); AddEdge(i,x);
    }
    rep(i,1,m) ask[i].read();
    solve();
    return 0;
}
相關文章
相關標籤/搜索