zoukankan      html  css  js  c++  java
  • [SDOI2018]战略游戏

    题目描述

    省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏。
    这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着道路走到
    任意其他城市。现在小C已经占领了其中至少两个城市,小Q可以摧毁一个小C没占领的城市,同时摧毁所有连接这
    个城市的道路。只要在摧毁这个城市之后能够找到某两个小C占领的城市u和v,使得从u出发沿着道路无论如何都不
    能走到v,那么小Q就能赢下这一局游戏。
    小Q和小C一共进行了q局游戏,每一局游戏会给出小C占领的城市集合S
    你需要帮小Q数出有多少个城市在他摧毁之后能够让他赢下这一局游戏。
    题解
    如果这是一棵树,那么做法就是直接对询问点见虚树,统计包含树中的点的最小联通块的大小。
    现在它是一张无向图,那么就把圆方树建出来,考虑一条路径经过了圆->方->圆点,那么那两个圆点割点,应对答案有1的贡献,方点的贡献为0。
    代码
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<algorithm>
    #define N 200009
    using namespace std;
    typedef long long ll;
    int dfn[N],head[N],tot,dis[N],n,low[N],ans,num,st[N],top,rbs[N],a[N];
    bool vis[N];
    inline ll rd(){
        ll x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    struct edge{int n,to;}e[N<<1];
    inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
    vector<int>vec[N],ed[N];
    inline bool cmp(int a,int b){return dfn[a]<dfn[b];}
    struct LCA{
    int top[N],size[N],son[N],fa[N],deep[N];
    void clear(){memset(deep,0,sizeof(deep));memset(top,0,sizeof(top));memset(son,0,sizeof(son));memset(fa,0,sizeof(fa));}
    void dfs(int u){
        size[u]=1;dis[u]=dis[fa[u]]+(u<=n);
        for(int i=0;i<vec[u].size();++i){
            int v=vec[u][i];
            fa[v]=u;deep[v]=deep[u]+1;
            dfs(v);size[u]+=size[v];
            if(size[v]>size[son[u]])son[u]=v;
        }
    }
    void dfs2(int u){
        dfn[u]=++dfn[0];if(!top[u])top[u]=u;
        if(son[u])top[son[u]]=top[u],dfs2(son[u]);
        for(int i=0;i<vec[u].size();++i){
          int v=vec[u][i];
          if(v!=fa[u]&&v!=son[u])dfs2(v);
        }
    }
    inline int getlca(int u,int v){
        while(top[u]!=top[v]){
            if(deep[top[u]]<deep[top[v]])swap(u,v);
            u=fa[top[u]];
        }
        return deep[u]<deep[v]?u:v;
    }
    }lca;
    void tarjan(int u,int fa){
        dfn[u]=low[u]=++dfn[0];vis[u]=1;st[++top]=u;
        for(int i=head[u];i;i=e[i].n)if((i^fa)!=1){
            int v=e[i].to;if(dfn[v]>dfn[u])continue;
            if(!dfn[v]){
                tarjan(v,i);
                low[u]=min(low[u],low[v]);
            }
            else if(vis[v])low[u]=min(low[u],dfn[v]);
            if(dfn[u]==low[v]){
                ++num;vec[u].push_back(num);//cout<<u<<" "<<num<<endl;
                while(st[top]!=v){
                    vec[num].push_back(st[top]);//cout<<num<<" "<<st[top]<<endl;
                    vis[st[top]]=0;top--;
                }
                vec[num].push_back(v);vis[v]=0;top--;//cout<<num<<" "<<v<<endl;
            }
            if(low[v]>dfn[u]){
                vec[u].push_back(v);
                top--;vis[v]=0;
            }
        }
    }
    void dfs(int u){
        for(int i=0;i<ed[u].size();++i){
            int v=ed[u][i];
            dfs(v);
            ans+=dis[v]-dis[u]; 
            if(vis[v]&&v<=n)ans--;
        }
    }
    inline void init(){
        tot=1;top=0;
        memset(head,0,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(dis,0,sizeof(dis));
        lca.clear();
    }
    inline void solve(){
        n=rd();int m=rd();int u,v;
        init();
        for(int i=1;i<=m;++i){
            u=rd();v=rd();
            add(u,v);add(v,u);
        } 
        num=n;
        tarjan(1,0);
        memset(dfn,0,sizeof(dfn));
        top=0;
        lca.dfs(1);lca.dfs2(1);
        memset(vis,0,sizeof(vis));
        int q=rd();
        while(q--){
            int s=rd();ans=0;
            for(int i=1;i<=s;++i)a[i]=rd(),vis[a[i]]=1;
            sort(a+1,a+s+1,cmp);
            st[top=1]=rbs[rbs[0]=1]=a[1];int root=a[1];
            for(int i=2;i<=s;++i){
                int x=a[i];//cout<<x<<"guiu"<<endl;
                int l=lca.getlca(x,st[top]);
                if(l==st[top]){st[++top]=x;rbs[++rbs[0]]=x;continue;}
                while(top>1){
                    int xx=st[top],yy=st[top-1];
                    if(dfn[yy]<=dfn[l]){
                        ed[l].push_back(xx);//cout<<l<<" "<<xx<<endl;
                        top--;break;
                    }
                    ed[yy].push_back(xx);top--;//cout<<yy<<" "<<xx<<endl;
                }
                if(dfn[l]<dfn[st[top]]){
                    if(dfn[l]<dfn[root])root=l;
                //    cout<<l<<" "<<st[top]<<endl;
                    ed[l].push_back(st[top]);top--;
                }
                if(l!=st[top])st[++top]=l,rbs[++rbs[0]]=l;
                st[++top]=x;rbs[++rbs[0]]=x; 
            }
            while(top>1){
            //    cout<<st[top-1]<<" "<<st[top]<<endl;
                ed[st[top-1]].push_back(st[top]);
                top--;
            }
            if(!vis[root]&&root<=n)ans++;
            dfs(root);
            printf("%d
    ",ans);
            while(rbs[0]){
                int x=rbs[rbs[0]];
                vis[x]=0;ed[x].clear();rbs[0]--;
            }        
        } 
        for(int i=1;i<=num;++i)vec[i].clear();
    }
    int main(){
        int T=rd();
        while(T--)solve();
        return 0;
    } 

    这里的圆方树不能随便的建,只能对每个点双开一个。、

    具体建法为:对于非点双内的边,直接连,并且弹栈。

        if(low[v]>dfn[u]){
                vec[u].push_back(v);
                top--;vis[v]=0;
            }

    对于每个割顶,新开一个节点,然后边弹栈边连边。

    if(dfn[u]==low[v]){
                ++num;vec[u].push_back(num);
                while(st[top]!=v){
                    vec[num].push_back(st[top]);
                    vis[st[top]]=0;top--;
                }
                vec[num].push_back(v);vis[v]=0;top--;
            }

    而且我们对于每个点双都只能算一次,为了避免算重,我们需要特判一下。

    if(dfn[v]>dfn[u])continue
  • 相关阅读:
    4.2Python数据类型(2)之布尔类型
    4.1Python数据类型(1)之数值类型
    AvalonJS+MVVM实战部分源码
    数据库的总结
    面向对象的Java实现
    静态HTML总结
    JS总结
    JSP开发Web应用系统
    使用C#开发数据库应用程序
    深入.NET平台和C#编程
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10384724.html
Copyright © 2011-2022 走看看