luogu P4116 Qtree3

題目描述

給出N個點的一棵樹(N-1條邊),節點有白有黑,初始全爲白

有兩種操作:

0 i : 改變某點的顏色(原來是黑的變白,原來是白的變黑)

1 v : 詢問1到v的路徑上的第一個黑點,若無,輸出-1

輸入格式

第一行 N,Q,表示N個點和Q個操作

第二行到第N行N-1條無向邊

再之後Q行,每行一個操作"0 i" 或者"1 v" (1 ≤ i, v ≤ N).

輸出格式

對每個1 v操作輸出結果


考慮只對於一條到根的路徑的情況:

如果給路徑加了一個黑點,那麼有兩種情況:一是這個黑點深度不是最小的,那麼我們不用管它;二是這個黑點是深度最小的黑點,那麼我們需要對這條路徑的信息進行更新。如果給路徑刪了一個黑點的話類似。

所以對於一條路徑的情況,我們需要一個支持維護最小值、加入和刪除點的數據結構。那麼堆可以勝任。

那麼考慮完整的樹的情況:

不難想到對於每個點到根節點的路徑都維護一個堆,那麼一共要維護N個堆,每次修改最多改N個點的信息(樹爲一條鏈,修改根節點)。複雜度顯然是我們不能接受的。

由於樹鏈剖分之後每一條路徑都可以表示成幾個鏈子拼起來的形式,所以我們可以對原樹進行重鏈剖分。然後我們只需要對於每條鏈子都維護一個堆即可。

時間複雜度爲O(NlogNlogN)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#define maxn 100001
#define maxm 300001
using namespace std;
int n,m;
bool col[maxn];
inline int read(){
    register int x(0),f(1); register char c(getchar());
    while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}

struct edge{
    int to,next;
    edge(){}
    edge(const int &_to,const int &_next){ to=_to,next=_next; }
}e[maxn<<1];
int head[maxn],k;
inline void add(const int &u,const int &v){ e[k]=edge(v,head[u]),head[u]=k++; }

int size[maxn],dep[maxn],fa[maxn],son[maxn];
int dfn[maxn],id[maxn],top[maxn],tot;
void dfs_getson(int u){
    size[u]=1;
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==fa[u]) continue;
        fa[v]=u,dep[v]=dep[u]+1;
        dfs_getson(v),size[u]+=size[v];
        if(size[v]>size[son[u]]) son[u]=v;
    }
}
void dfs_rewrite(int u,int tp){
    dfn[u]=++tot,id[tot]=u,top[u]=tp;
    if(son[u]) dfs_rewrite(son[u],tp);
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v!=fa[u]&&v!=son[u]) dfs_rewrite(v,v);
    }
}
set<int> ans[maxn];

int main(){
    memset(head,-1,sizeof head);
    n=read(),m=read();
    for(register int i=1;i<n;i++){
        int u=read(),v=read();
        add(u,v),add(v,u);
    }
    dfs_getson(1),dfs_rewrite(1,1);
    
    for(register int i=1;i<=m;i++){
        int op=read(),u=read();
        if(op==0){
            col[u]^=1;
            if(col[u]) ans[top[u]].insert(dfn[u]);
            else ans[top[u]].erase(dfn[u]);
        }else{
            int v=0x3f3f3f3f,k;
            while(top[u]!=1){
                k=*ans[top[u]].begin();
                if(ans[top[u]].size() && dep[id[k]]<=dep[u]) v=id[k];
                u=fa[top[u]];
            }
            k=*ans[1].begin();
            if(ans[1].size() && dep[id[k]]<=dep[u]) v=id[k];
            printf("%d\n",v==0x3f3f3f3f?-1:v);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章