zoukankan      html  css  js  c++  java
  • [BZOJ 4551][Tjoi2016&Heoi2016]树(并查集)

    Description

    在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下
    两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个
    结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖
    先)你能帮帮他吗?

    Solution

    还是非常巧妙的思维

    离线,先记录每个点的标记数,倒序处理询问,遇到打标记就把标记数减一,对于标记数为0的点就用并查集与它的父节点合并

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #define MAXN 100005
    using namespace std;
    int n,q,head[MAXN],cnt=0,f[MAXN],father[MAXN],num[MAXN],sign[MAXN];
    char opt[MAXN];
    vector<int>v;
    struct Node
    {
        int next,to;
    }Edges[MAXN*2];
    void addedge(int u,int v)
    {
        Edges[++cnt].next=head[u];
        head[u]=cnt;
        Edges[cnt].to=v;
    }
    int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0';c=getchar();
        }
        return x*f;
    }
    int find(int x)
    {
        if(father[x]==x)return x;
        return father[x]=find(father[x]);
    }
    void dfs(int u)
    {
        if(!sign[u])father[u]=find(f[u]); 
        for(int i=head[u];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(v==f[u])continue;
            f[v]=u;
            dfs(v);
        }
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        n=read(),q=read();
        for(int i=1;i<n;i++)
        {
            int u=read(),v=read();
            addedge(u,v);
            addedge(v,u);
            father[i]=i;
        }
        father[n]=n,sign[1]++;
        for(int i=1;i<=q;i++)
        {
            opt[i]=getchar();
            while(opt[i]!='Q'&&opt[i]!='C')opt[i]=getchar();
            num[i]=read();
            if(opt[i]=='C')sign[num[i]]++;
        }
        dfs(1);
        for(int i=q;i>0;i--)
        {
            if(opt[i]=='C')
            {
                sign[num[i]]--;
                if(!sign[num[i]])
                father[num[i]]=find(f[num[i]]);
            }
            else
            v.push_back(find(num[i]));
        }
        for(int i=v.size()-1;i>=0;i--)
        printf("%d
    ",v[i]);
        return 0;
    } 
  • 相关阅读:
    brctl 使用说明
    Flash文件系统介绍和平台采用squashfs+ubifs原因
    xargs
    svn的常用命令
    shell中的if用法
    shell中单双引号
    删除文件中的 ^M 字符
    博客园添加live2d看板娘
    IOS 自定义转场动画
    rails
  • 原文地址:https://www.cnblogs.com/Zars19/p/6872287.html
Copyright © 2011-2022 走看看