• [bzoj4551][Tjoi2016][Heoi2016]树


    Description

    在2016年,佳媛姐姐刚刚学习了树,非常开心。

    现在她想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作:

    1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记);

    2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖

    先).

    你能帮帮她吗?

    Input

    输入第一行两个正整数NQ,分别表示节点个数和操作次数.

    接下来N-1行,每行两个正整数u,v,表示uv有一条有向边.

    接下来Q行,形如“oper;num”.oper为“C”时,表示这是一个标记操作;

    oper为“Q”时,表示这是一个询问操作.

    Output

    输出一个正整数,表示结果.

    Sample Input

    5 5
    1 2
    1 3
    2 4
    2 5
    Q 2
    C 2
    Q 2
    Q 5
    Q 3

    Sample Output

    1
    2
    2
    1

    HINT

    1$leq$N,Q$leq$10^5,1$leq$u,v$leq$n

    Solution

    正难则反,对于所有操作逆序离线处理.

    先记录每个节点被打过几次标记,预处理出每个节点最后时刻最近的打了标记的祖先.

    从后往前消除标记,如果当前点的标记被消除完,则这个点最近的打了标记的祖先为它父亲最近的打了标记的祖先,并查集可实现.

    #include<cmath>
    #include<ctime>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 100005
    using namespace std;
    struct graph{
        int nxt,to;
    }e[N<<1];
    struct quest{
        int t,x;
    }b[N];
    int a[N],f[N],g[N],fa[N],ans[N],n,m,q,t,x,cnt;
    stack<int> s;
    inline int read(){
        int ret=0;char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)){
            ret=(ret<<1)+(ret<<3)+c-'0';
            c=getchar();
        }
        return ret;
    }
    inline int rc(){
        char c=getchar();
        while(c!='Q'&&c!='C') c=getchar();
        if(c=='C') return 1;
        return 2;
    }
    inline void addedge(int x,int y){
        e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
    }
    inline void dfs(int u){
        fa[u]=f[u]=1;s.push(u);
        while(!s.empty()){
            u=s.top();s.pop();
            for(int i=g[u];i;i=e[i].nxt)
                if(fa[u]!=e[i].to){
                    fa[e[i].to]=u;s.push(e[i].to);
                    if(!a[e[i].to]) f[e[i].to]=f[u];
                    else f[e[i].to]=e[i].to;
                }
        }
    }
    inline int gf(int k){
        if(f[k]==k) return k;
        return f[k]=gf(f[k]);
    }
    inline void init(){
        n=read();q=read();
        for(int i=1,j,k;i<n;++i){
            j=read();k=read();
            addedge(j,k);addedge(k,j);
        }
        for(int i=1;i<=q;++i){
            b[i].t=rc();b[i].x=read();
            if(b[i].t&1) ++a[b[i].x];
        }
        ++a[1];dfs(1);cnt=0;
        for(int i=q,j,k;i;--i){
            if(b[i].t&1){
                if(!(--a[b[i].x])){
                    f[b[i].x]=gf(f[fa[b[i].x]]);
                }
            }
            else ans[++cnt]=gf(f[b[i].x]);
        }
        for(int i=cnt;i;--i)
            printf("%d
    ",ans[i]);
    }
    int main(){
        freopen("tree.in","r",stdin);
        freopen("tree.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    Linux 学习笔记1
    Openstack中的LoadBalancer(负载均衡)功能使用实例
    分析事务与锁3
    MemoryStream
    JBPM4学习之路2:流程部署
    在MongoDB中一起使用$or和sort()
    使用avalon msui绑定实现基于组件的开发
    深度剖析Byteart Retail案例:应用程序的配置
    最年轻的系统分析员的考试心得
    linux学习体会,献给初学者
  • 原文地址:https://www.cnblogs.com/AireenYe/p/6045002.html
Copyright © 2020-2023  润新知