• 2016-2017 ACM-ICPC, NEERC, Northern Subregional Contest G(gym/101142 G)


    gym/101142 G

    题意:一棵树,给出每个点的父亲节点,叶子节点是house,1是根节点,也是水源,现在有2个操作,+ x表示劫匪入侵第x个house, - x表示劫匪退出第x个house,每次操作后求最少切断几个边,可以把劫匪入侵的house的水源切断,并且求出收到影响的普通house的最小个数

    思路:LCA, 根节点下面每一个节点的子树上面,如果有2个或以上的house被入侵,那么最多只需要切断一条边即可,切断的边是这个子树下面所有被入侵的house的LCA与LCA的父亲连接的边,

    关于如何快速求 p 个点的最近公共祖先(LCA),只要对该子树被歹徒占领的点中 dfs 序最小的点和最大的点求 LCA 。

    对根节点下每一个子树动态维护一个set即可,set用于维护这个子树下面dfs序最大和最小的节点,代码比较不好写

    AC代码:

    #include "iostream"
    #include "iomanip"
    #include "string.h"
    #include "stack"
    #include "queue"
    #include "string"
    #include "vector"
    #include "set"
    #include "map"
    #include "algorithm"
    #include "stdio.h"
    #include "math.h"
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
    #define mem(a,x) memset(a,x,sizeof(a))
    #define step(x) fixed<< setprecision(x)<<
    #define mp(x,y) make_pair(x,y)
    #define pb(x) push_back(x)
    #define ll long long
    #define endl ("
    ")
    #define ft first
    #define sd second
    #define lrt (rt<<1)
    #define rrt (rt<<1|1)
    using namespace std;
    const ll mod=1e9+7;
    const ll INF = 1e18+1LL;
    const int inf = 1e9+1e8;
    const double PI=acos(-1.0);
    const double eps=1e-9;
    const int N=1e5+100;
    
    set<pair<int,int> > se[N];
    vector<int> G[N];
    pair<int,int> in[N];
    int cnt,top[N], son[N], siz[N], dep[N], vis[N], hos[N], ins[N], ans[N], fa[N];
    void dfs0(int u, int t){
        siz[u]=1;
        ins[u]=t;
        dep[u]=dep[fa[u]]+1;
        if(vis[u]==0) hos[u]=1;
        for(auto v : G[u]){
            if(u==1) t=v;
            dfs0(v, t);
            siz[u]+=siz[v];
            hos[u]+=hos[v];
            if(siz[son[u]] < siz[v]) son[u]=v;
        }
    }
    
    void dfs1(int u, int tp){
        in[u].ft=cnt++;
        in[u].sd=u;
        top[u]=tp;
        if(son[u]!=0) dfs1(son[u], tp);
        for(auto v : G[u]){
            if(v!=son[u]) dfs1(v,v);
        }
    }
    
    int LCA(int u, int v){
        while(top[u] != top[v]){
            if(dep[top[u]] > dep[top[v]]) swap(u,v);
            v=fa[top[v]];
        }
        if(dep[u] > dep[v]) swap(u, v);
        return u;
    }
    
    int main(){
        freopen("gangsters.in","r",stdin);
        freopen("gangsters.out","w",stdout);
        int n,m,u,out=0, out1=0;
        char s[10];
        scanf("%d %d",&n,&m);
        for(int i=2; i<=n; ++i){
            scanf("%d",&u);
            G[u].pb(i); fa[i]=u; vis[u]=1;
        }
        dfs0(1,1);
        dfs1(1,1);
        for(int i=1; i<=m; ++i){
            scanf("%s %d", s, &u);
            if(s[0]=='+'){
                se[ins[u]].insert(in[u]);
                if(se[ins[u]].size()==1){
                    ans[ins[u]]=0, out1++;
                }
                else{
                    int lca=LCA(se[ins[u]].begin()->sd, se[ins[u]].rbegin()->sd);
                    out-=ans[ins[u]];
                    ans[ins[u]]=hos[lca]-se[ins[u]].size();
                    out+=ans[ins[u]];
                }
            }
            else{
                se[ins[u]].erase(in[u]);
                if(se[ins[u]].size()<2){
                    out-=ans[ins[u]];
                    ans[ins[u]]=0;
                    if(se[ins[u]].size()==0) out1--;
                }
                else{
                    int lca=LCA(se[ins[u]].begin()->sd, se[ins[u]].rbegin()->sd);
                    out-=ans[ins[u]];
                    ans[ins[u]]=hos[lca]-se[ins[u]].size();
                    out+=ans[ins[u]];
                }
            }
            printf("%d %d
    ",out1, out);
        }
        return 0;
    }
  • 相关阅读:
    鼠标经过显示边框
    特殊字符
    HTML 列表
    embed 引入网上视频
    锚点定位
    盒子阴影
    Map的四种遍历方式
    Glide的 java.lang.RuntimeException: Expected instanceof GlideModule, but found:X.GlideModule@2e4554f
    Java标识符的命名规则
    django入门与实践
  • 原文地址:https://www.cnblogs.com/max88888888/p/7823053.html
Copyright © 2020-2023  润新知