bzoj3569 DZY Loves Chinese II & bzoj3237 [AHOI2013] 连通图

给一个无向连通图,多次询问,每次询问给 k 条边,问删除这 k 条边后图的连通性,对于 bzoj3237 可以离线,对于 bzoj3569 强制在线

$n,m,q \leq 500000,k \leq 15$

sol:

离线的话很好做,xjb 分治就行了,大概就是 bzoj4025 二分图那题改一改,用一个带权并查集维护连通块大小,当然删除时间最大生成树也是可以做的

 

在线的话,我们需要一些神仙操作

首先,随便搞出这个图的一棵生成树,对于每个非树边,我们给它随机一个权值

然后对于每条树边,我们让它的权值为覆盖它的所有非树边异或和

我们发现图不连通当且仅当一条树边和所有覆盖它的非树边都被删除

因为树边权值 xor 所有覆盖它的非树边权值异或和 = 0

于是问题变成了:“给你一个边集,判断是否有一个子集异或和为 0 ”

这个就要用到线性基的那一套理论

我们知道求线性基的时候可以求出一组极大线性无关集

看这个线性无关集大小是否为 k 即可

求线性基可以高斯消元

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 500010;
int n,m;
int first[maxn],to[maxn << 1],nx[maxn << 1],val[maxn << 1],cnt = 1;
inline void add(int u,int v)
{
    to[++cnt] = v;
    nx[cnt] = first[u];
    first[u] = cnt;
}
inline void ins(int u,int v){add(u,v);add(v,u);}
int bin[35],vis[maxn],v[maxn];
int lastans,a[50];
inline void maketree(int x,int fa)
{
    vis[x] = 1;
    for(int i=first[x];i;i=nx[i])
    {
        if(to[i] == fa)continue;
        if(!vis[to[i]])maketree(to[i],x);
        else if(!val[i >> 1])
        {
            val[i >> 1] = rand();
            v[x] ^= val[i >> 1];
            v[to[i]] ^= val[i >> 1];
        }
    }
}
inline void dfs(int x)
{
    vis[x] = 1;
    for(int i=first[x];i;i=nx[i])
    {
        if(vis[to[i]])continue;
        dfs(to[i]);v[x] ^= v[to[i]];
        val[i >> 1] = v[to[i]];
    }
}
int Gauss_Jordan(int n)
{
    int now = 1;
    for(int i=30;i>=0;i--)
    {
        int j = now;
        while(j <= n &&!(a[j] & (1 << (i - 1)))) j++;
        if(j == n+1) continue;
        if(j != now) swap(a[now],a[j]);
        for(int k=1;k<=n;k++)
            if(k != now && (a[k] & (1 << (i - 1)))) a[k] ^= a[now];
        now++;
    }
    now--;
    return now;
}
int main()
{
    srand((unsigned long long)new char);
    n = read(),m = read();
    for(int i=1;i<=m;i++)
    {
        int u = read(),v = read();
        ins(u,v);
    }maketree(1,0);
    memset(vis,0,sizeof(vis));
    dfs(1);int q = read();
    while(q--)
    {
        int k = read(),top = 0;
        while(k--)a[++top] = val[read() ^ lastans];
        int res = Gauss_Jordan(top);
        if(res < top)puts("Disconnected");
        else lastans++,puts("Connected");
    }
}
View Code

 

posted @ 2018-12-03 14:39  探险家Mr.H  阅读(228)  评论(0编辑  收藏  举报