[题解]luogu P4116 Qtree3

终于来到了Qtree3, 其实这是Qtree系列中最简单的一道题,并不需要线段树, 只要树链剖分的一点思想就吼了。

对于树链剖分剖出来的每一根重链,在重链上维护一个Set就好了, 每一个Set里存的都是重链中的黑点, 深度就是关键字。

考虑每一种操作


0 : 改变颜色

    在他所在的重链上插入一个黑点或者earse掉

1 : 查询

    就像树链剖分一样, 一直往上跳重链头然后更新答案即可
   

代码较短

#include <bits/stdc++.h>
#define maxn 101000
#define maxm 303000
using namespace std;

template<class T>
inline void read(T &a){
    T s = 0, w = 1;
    char c = getchar();
    while(c < '0' || c  > '9') {if(c == '-') w = -1; c = getchar();}
    while(c >= '0' && c <= '9') {s = (s << 1) + (s << 3) + (c ^ 48); c = getchar();}
    a = s*w;
}

static int n,q;
static int head[maxn], net[maxm], to[maxm],tot;

inline void add(int x, int y){
    net[++tot] = head[x], head[x] = tot, to[tot] = y;
}

static int dfn[maxn],tid[maxn], fat[maxn], size[maxn], son[maxn], deep[maxn];
static int top[maxn], cnt;

set<int> Ans[maxn];

void dfs1(int x, int fa){
    size[x] = 1;
    son[x] = 0; size[0] = 0;
    fat[x] = fa;
//  printf("%d\n", x);
    for (int i = head[x]; i; i = net[i]){
        int v = to[i];
        if(v == fa) continue;
        deep[v] = deep[x] + 1;
        dfs1(v, x);
        size[x] += size[v];
        if(size[v] > size[son[x]]) son[x] = v;
    }
}
void dfs2(int x, int fa, int t){
    dfn[++cnt] = x;
    //printf("%d %d %d\n", cnt, x, t);
    tid[x] = cnt;
    top[x] = t;
    if(!son[x]) return;
    dfs2(son[x], x, t);
    for (int i = head[x]; i; i = net[i]){
        int v = to[i];
        if(v == fa || v == son[x]) continue;
        dfs2(v, x, v);
    }
}


int col[maxn];
int main(){
    #ifndef ONLINE_JUDGE
        freopen("p4116.in","r", stdin);
        freopen("p4116.out","w", stdout);
    #endif
    read(n); read(q);
//  printf("%d\n", n); return 0;
    for (int i = 1; i < n; i++){
        int x, y;
        read(x); read(y);
        add(x, y); add(y, x);
    }
    dfs1(1, 0);
    dfs2(1, 0, 1); 
    for (int i = 1; i <= q; i++){
        int opt, x;
        read(opt); read(x);
        if(opt == 0){
            col[x] ^= 1;
            if(col[x] == 1) Ans[top[x]].insert(tid[x]);
             else Ans[top[x]].erase(tid[x]);
        }
        else{
            int ans = 0x3f3f3f3f;
            while(x){
                int k = *Ans[top[x]].begin();
                if(Ans[top[x]].size())
                    if(deep[dfn[k]] <= deep[x]) ans = dfn[k];
                x = fat[top[x]];
            }
            printf("%d\n", ans == 0x3f3f3f3f ? -1: ans);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Ender-zzm/p/10541426.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值