[高斯消元 线性基 生成树 随机化权值Xor] BZOJ 3569 DZY Loves Chinese II

30 篇文章 0 订阅
26 篇文章 0 订阅

很好的建图姿势:

我们找到这个图的任意一棵生成树 然后对于每条非树边将其的权值赋为一个随机数

对于每条树边 我们将这条树边的权值设为所有覆盖这条树边的边权的异或和

那么图不连通当且仅当删除一条树边和覆盖这条树边的所有边集 而由于刚才的处理一条树边和覆盖这条边的所有边集的异或和为零

于是问题转化成了对于给定的k条边是否存在一个边权的异或和为零的子集 果断高斯消元 由于使用了随机化所以碰撞率极低


还不是很熟悉高斯消元那一套理论啊


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
    return *p1++;
}

inline void read(int &x){
    char c=nc(),b=1;
    for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
    for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=100005,M=500005;

struct edge{
    int u,v; int next;
};

edge G[M<<1];
int head[N],inum=1;

inline void add(int u,int v,int p){
    G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}

int n,m;
int a[M],b[M];
int vst[N];

#define V G[p].v
inline void dfs1(int u,int fa){
    vst[u]=1;
    for (int p=head[u];p;p=G[p].next)
        if (V!=fa)
        {
            if (!vst[V])
                dfs1(V,u);
            else if (!~a[p>>1])
            {
                a[p>>1]=rand();
                b[V]^=a[p>>1]; b[u]^=a[p>>1];
            }
        }
}

inline void dfs2(int u,int fa){
    vst[u]=1;
    for (int p=head[u];p;p=G[p].next)
        if (V!=fa && !vst[V])
        {
            dfs2(V,u);
            a[p>>1]=b[V];
            b[u]^=b[V];
        }
}

int K,s[M];

inline void Gauss()
{
    int k=0,i;
    for (int j=1<<30;j;j>>=1)
    {
        for (i=k+1;i<=K;i++)
            if (s[i]&j)
                break;
        if (i==K+1) continue;
        swap(s[i],s[++k]);
        for (int i=k+1;i<=K;i++)
            if (s[i]&j)
                s[i]^=s[k];
    }
}

int main()
{
    int x,y,Q,lastans=0;
    srand(10086);
    freopen("t.in","r",stdin);
    freopen("t.out","w",stdout);
    read(n); read(m);
    for (int i=1;i<=m;i++)
        read(x),read(y),add(x,y,++inum),add(y,x,++inum);
    memset(a,-1,sizeof(a));
    dfs1(1,0);
    cl(vst);
    dfs2(1,0);
    read(Q);
    while (Q--)
    {
        read(K);
        for (int i=1;i<=K;i++)
            read(x),s[i]=a[x^lastans];
        Gauss();
        lastans+=(bool)s[K];
        if (s[K])
            printf("Connected\n");
        else
            printf("Disconnected\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值