zoukankan      html  css  js  c++  java
  • 【loj#2524】【bzoj5303】 [Haoi2018]反色游戏(圆方树)

      题目传送门:loj bzoj

      题意中的游戏方案可以转化为一个异或方程组的解,将边作为变量,点作为方程,因此若方程有解,方程的解的方案数就是2的自由元个数次方。我们观察一下方程,就可以发现自由元数量=边数-点数+连通块数,或者换句话说,若对原图的每个联通块指定一棵生成树,那么确定了生成树之外的边是否进行操作,那么生成树内的边的操作方案就是一定存在并唯一确定的。

      那么我们就只需要判断一下什么样的图无解。我们发现每对一条边进行操作,原图内的黑点数量奇偶性不变,那么我们只需判断图中的是否存在某个联通块有奇数个黑点,若存在即无解。

      加上了删点操作后,我们可以用圆方树来维护连通块信息。因为圆方树的连通性与原图上的连通性相互对应,删除单个点之后,原图被新分成的连通块就是圆方树删除对应点的连通块,那么使用圆方树就可以快速维护删除单个点的连通块信息。

      代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #define ll long long
    #define inf 0x3f3f3f3f
    #define mod 1000000007
    #define maxn 200010
    inline ll read()
    {
        ll x=0; char c=getchar(),f=1;
        for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
        for(;'0'<=c&&c<='9';c=getchar())x=x*10+c-'0';
        return x*f;
    }
    inline void write(ll x)
    {
        static int buf[20],len; len=0;
        if(x<0)x=-x,putchar('-');
        for(;x;x/=10)buf[len++]=x%10;
        if(!len)putchar('0');
        else while(len)putchar(buf[--len]+'0');
    }
    inline void writeln(ll x){write(x); putchar('
    ');}
    inline void writesp(ll x){write(x); putchar(' ');}
    struct edge{
        int to,nxt;
    };
    struct Graph{
        edge e[4*maxn];
        int fir[2*maxn],deg[2*maxn];
        int tot;
        inline void clear()
        {
            memset(fir,255,sizeof(fir)); tot=0;
            memset(deg,0,sizeof(deg));
        }
        inline void add_edge(int x,int y)
        {
            e[tot].to=y; e[tot].nxt=fir[x]; fir[x]=tot++;
            ++deg[x];
        }
    }G,T;
    int dfn[maxn],low[maxn],st[maxn],ans[maxn];
    int val[2*maxn],size[2*maxn],fa[2*maxn],rt[2*maxn];
    char s[maxn];
    int n,m,tot,tp,cnt;
    inline ll power(ll a,ll b)
    {
        ll ans=1;
        for(;b;b>>=1,a=a*a%mod)
            if(b&1)ans=ans*a%mod;
        return ans;
    }
    void tarjan(int now,int last)
    {
        dfn[now]=low[now]=++tot; st[++tp]=now;
        for(int i=G.fir[now];~i;i=G.e[i].nxt)
            if(i!=(last^1)){
                if(!dfn[G.e[i].to]){
                    tarjan(G.e[i].to,i);
                    low[now]=std::min(low[now],low[G.e[i].to]);
                    if(low[G.e[i].to]>=dfn[now]){
                        ++cnt;
                        T.add_edge(now,cnt); T.add_edge(cnt,now);
                        do{
                            T.add_edge(st[tp],cnt); T.add_edge(cnt,st[tp]);
                        }while(st[tp--]!=G.e[i].to);
                    }
                }
                else low[now]=std::min(low[now],dfn[G.e[i].to]);
            }
    }
    void dfs(int now,int root)
    {
        rt[now]=root;
        size[now]=val[now];
        for(int i=T.fir[now];~i;i=T.e[i].nxt)
            if(T.e[i].to!=fa[now]){
                fa[T.e[i].to]=now;
                dfs(T.e[i].to,root);
                size[now]+=size[T.e[i].to];
            }
    }
    void work()
    {
        n=read(); m=read();
        G.clear();
        for(int i=1;i<=m;i++){
            int x=read(),y=read();
            G.add_edge(x,y); G.add_edge(y,x);
        }
        scanf("%s",s);
        memset(val,0,sizeof(val));
        for(int i=1;i<=n;i++)
            val[i]=(s[i-1]=='1');
        T.clear();
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        tot=tp=0; cnt=n;
        for(int i=1;i<=n;i++)
            if(!dfn[i]){
                tarjan(i,-1);
                fa[i]=-1;
                dfs(i,i);
            }
        int odd=0,block=0;
        for(int i=1;i<=n;i++)
            if(fa[i]==-1)odd+=(size[i]&1),++block;
        ans[0]=(odd?0:power(2,m-n+block));
        for(int i=1;i<=n;i++){
            odd-=(size[rt[i]]&1);
            int flag=1;
            for(int j=T.fir[i];~j;j=T.e[j].nxt)
                if(T.e[j].to!=fa[i]&&(size[T.e[j].to]&1)){
                    flag=0; break;
                }
            if(odd||!flag||((size[rt[i]]-size[i])&1))ans[i]=0;
            else ans[i]=power(2,(m-G.deg[i])-(n-1)+(block+T.deg[i]-1));
            odd+=(size[rt[i]]&1);
        }
        for(int i=0;i<=n;i++)
            writesp(ans[i]);
        putchar('
    ');
    }
    int main()
    {
        int T=read();
        while(T--)work();
        return 0;
    }
    反色游戏
  • 相关阅读:
    EXT 中的Grid实例
    JS正则表达式详解 转
    EXTJS制作的嵌套表格实例(点击一行,展开下面的子表)
    动态加载JS文件
    ExtJs WebService Json序列化(扩展JavaScriptSerializer类)收藏
    转载 悟透JavaScript
    《ExtJS2.0实用简明教程》之与服务器交互 extjs Ext.Ajax.request({}) params:
    Ext 动态添加grid 列数
    API中form相关
    生成用户界面
  • 原文地址:https://www.cnblogs.com/quzhizhou/p/11483149.html
Copyright © 2011-2022 走看看