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

    5329: [Sdoi2018]战略游戏

    Time Limit: 30 Sec  Memory Limit: 512 MB
    Submit: 12  Solved: 9
    [Submit][Status][Discuss]

    Description

    省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏。
    这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着道路走到
    任意其他城市。现在小C已经占领了其中至少两个城市,小Q可以摧毁一个小C没占领的城市,同时摧毁所有连接这
    个城市的道路。只要在摧毁这个城市之后能够找到某两个小C占领的城市u和v,使得从u出发沿着道路无论如何都不
    能走到v,那么小Q就能赢下这一局游戏。
    小Q和小C一共进行了q局游戏,每一局游戏会给出小C占领的城市集合S
    你需要帮小Q数出有多少个城市在他摧毁之后能够让他赢下这一局游戏。

    Input

    第一行包含一个正整数T,表示测试数据的组数,
    对于每组测试数据,
    第一行是两个整数n和m,表示地图的城市数和道路数,
    接下来m行,每行包含两个整数u和v~(1<=u<v<=n)
    表示第u个城市和第v个城市之间有一条道路,同一对城市之间可能有多条道路连接,
    第m+1是一个整数q,表示游戏的局数,
    接下来q行,每行先给出一个整数|S|(2<=|S|<=n)
    表示小C占领的城市数量,然后给出|S|个整数s1,s2,...s|S|,(1<=s1<s2<s|S|<=n),表示小C占领的城市。
    1<= T<= 10,
    2<= n<= 10^5 且 n-1<= m<= 2*10^5,
    1<= q<= 10^5,
    对于每组测试数据,有Sigma|S|<= 2*10^5

    Output

    对于每一局游戏,输出一行,包含一个整数,表示这一局游戏中有多少个城市在小Q摧毁之后能够让他赢下这一局游戏。

    Sample Input

    7 6
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    3
    2 1 2
    3 2 3 4
    4 4 5 6 7
    6 6
    1 2
    1 3
    2 3
    1 4
    2 5
    3 6
    4
    3 1 2 3
    3 1 2 6
    3 1 5 6
    3 4 5 6

    Sample Output

    0
    1
    3
    0
    1
    2
    3
     
     
        考场上想出来发现是个圆方树。。。但是以前没写过怎么办啊QWQ
        不管了,硬钢吧23333
        (然后最后就神奇的钢出来了)
     
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<stack>
    #include<vector>
    #include<map>
    #include<tr1/unordered_map>
    #define ll long long
    #define pb push_back
    #define mid (l+r>>1)
    #define lc (o<<1)
    #define rc ((o<<1)|1)
    using namespace std;
    using namespace std::tr1;
    const int maxn=400005;
    vector<int> g[maxn];
    unordered_map<int,int> mmp[maxn];
    int T,n,m,num,hd[maxn],to[maxn*2],ne[maxn*2];
    int dfn[maxn],low[maxn],dc,cnt,rp[maxn],dy[maxn],dep[maxn];
    int siz[maxn],son[maxn],cl[maxn],F[maxn],L,Q,now[maxn],k,ans;
    int Lim[maxn*4],sum[maxn*4],le,ri,W,tag[maxn*4];
    struct lines{ int U,V;};
    stack<lines> s;
     
    inline int read(){
        int x=0; char ch=getchar();
        for(;!isdigit(ch);ch=getchar());
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
        return x;
    }
    void Wt(int x){ if(x<0) { Wt(-x); return;} if(x>=10) Wt(x/10); putchar(x%10+'0');}
    inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}
    inline void ADD(int x,int y){ g[x].pb(y),g[y].pb(x);}
     
    inline void init(){
        for(int i=0;i<=cnt;i++) g[i].clear(),mmp[i].clear();
        memset(hd,0,sizeof(hd)),num=0;
        memset(dfn,0,sizeof(dfn)),dc=0;
        memset(son,0,sizeof(son));
    }
     
    void dfs(int x,int fa){
        low[x]=dfn[x]=++dc;
        lines e;
        for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa){
            e=(lines){x,to[i]};
            if(!dfn[to[i]]){
                s.push(e);
                dfs(to[i],x),low[x]=min(low[x],low[to[i]]);
                 
                if(low[to[i]]>=dfn[x]){
                    cnt++;
                    for(;;){
                        e=s.top(),s.pop();
                        if(!mmp[e.U].count(cnt)) ADD(e.U,cnt),mmp[e.U][cnt]=1;
                        if(!mmp[e.V].count(cnt)) ADD(e.V,cnt),mmp[e.V][cnt]=1;
                        if(e.U==x&&e.V==to[i]) break;
                    }
                }
            }
            else if(dfn[to[i]]<low[x]){
                low[x]=dfn[to[i]];
                s.push(e);
            }
        }
    }
     
    void dfs1(int x,int fa){
        F[x]=fa,siz[x]=1;
        for(int i=g[x].size()-1,T;i>=0;i--){
            T=g[x][i];
            if(T==fa) continue;
             
            rp[T]=rp[x]+(T<=n),dep[T]=dep[x]+1;
            dfs1(T,x),siz[x]+=siz[T];
            if(!son[x]||siz[son[x]]<siz[T]) son[x]=T;
        }
    }
     
    void dfs2(int x,int tp){
        cl[x]=tp,dfn[x]=++dc,dy[dc]=x;
        if(!son[x]) return;
         
        dfs2(son[x],tp);
         
        for(int i=g[x].size()-1,t;i>=0;i--){
            T=g[x][i];
            if(T==F[x]||T==son[x]) continue;
             
            dfs2(T,T);
        }
    }
     
    void build(int o,int l,int r){
        sum[o]=tag[o]=0;
        if(l==r){ Lim[o]=(dy[l]<=n); return;}
        build(lc,l,mid),build(rc,mid+1,r);
        Lim[o]=Lim[lc]+Lim[rc];
    }
     
    inline void work1(int o){ sum[o]=Lim[o],tag[o]=1;}
    inline void work2(int o){ sum[o]=0,tag[o]=2;}
     
    inline void pushdown(int o){
        if(tag[o]==1){ work1(lc),work1(rc);}
        else if(tag[o]){ work2(lc),work2(rc);}
        tag[o]=0;
    }
     
    inline void maintain(int o){
        sum[o]=sum[lc]+sum[rc];
    }
     
    void update1(int o,int l,int r){
        if(l>=le&&r<=ri){ ans+=Lim[o]-sum[o],work1(o); return;}
        pushdown(o);
        if(le<=mid) update1(lc,l,mid);
        if(ri>mid) update1(rc,mid+1,r);
        maintain(o);
    }
     
    void update2(int o,int l,int r){
        if(l>=le&&r<=ri){ work2(o); return;}
        pushdown(o);
        if(le<=mid) update2(lc,l,mid);
        if(ri>mid) update2(rc,mid+1,r);
        maintain(o);
    }
     
    inline int LCA(int x,int y){
        while(cl[x]!=cl[y]){
            if(dep[cl[x]]>dep[cl[y]]) x=F[cl[x]];
            else y=F[cl[y]];
        }
         
        return dep[x]>dep[y]?y:x;
    }
     
    inline void paint(int x){
        while(x){
            le=dfn[cl[x]],ri=dfn[x];
            update1(1,1,cnt);
            x=F[cl[x]];
        }
    }
     
    inline void REV(int x){
        while(x){
            le=dfn[cl[x]],ri=dfn[x];
            update2(1,1,cnt);
            x=F[cl[x]];
        }   
    }
     
    inline void solve(){
        /*
        for(int i=1;i<=cnt;i++){
            cout<<i<<':'<<g[i].size()<<endl;
            for(int j=g[i].size()-1;j>=0;j--) printf("%d ",g[i][j]);
            puts("");
        }
        */
         
        memset(dfn,0,sizeof(dfn)),dc=0;
        rp[1]=1,dfs1(1,0),dfs2(1,1);
        build(1,1,cnt);
         
        Q=read();
        while(Q--){
            ans=L=0,k=read();
            for(int i=1;i<=k;i++){
                now[i]=read();
                if(!L) L=now[i]; else L=LCA(L,now[i]);
                paint(now[i]);
            }
             
            Wt(ans-rp[F[L]]-k),puts("");
             
            for(int i=1;i<=k;i++) REV(now[i]);
        }
    }
     
    int main(){
    //  freopen("game.in","r",stdin);
    //  freopen("game.out","w",stdout);
     
    //  freopen("data.in","r",stdin);
    //  freopen("data.out","w",stdout);
         
        int uu,vv;
        T=read();
        while(scanf("%d%d",&n,&m)==2){
            init(),cnt=n;
            for(int i=1;i<=m;i++){
                uu=read(),vv=read();
                add(uu,vv),add(vv,uu);
            }
             
            for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i,-1);
             
            solve();
        }
         
        return 0;
    }
    
  • 相关阅读:
    千万级规模高性能、高并发的网络架构经验分享
    CPU高问题排查
    Worker+MQ解惑
    HashMap解惑
    配置时间同步时,遇到同步无法成功的解决方法
    Django基础—— 1.WEB框架介绍
    html5兼容性问题
    jQuery基础——节点操作
    jQuery基础——基本操作
    jQuery基础——选择器
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9051699.html
Copyright © 2011-2022 走看看