BZOJ 3569 DZY Loves Chinese(BZOJ 3563) II 线性基

题目大意:给出一张n个点m条边的无向图。进行q次询问,问删掉某k条边后图是否联通。强制在线
N≤100000 M≤500000 Q≤50000 1≤K≤15

这题好神啊…

首先找出图中的一棵生成树,对于每一条非树边赋上一个随机值,每条树边等于覆盖它的非树边的权值的异或和,那么这个图不连通当存在一个删掉的边的子集的异或和为0。

线性基搞一下看能不能异或出0。

#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 100005
using namespace std;
int RAND() { return (rand()<<16)+rand(); }
struct Edge {
    int to,nxt;
    Edge() {}
    Edge(int _to,int _nxt):to(_to),nxt(_nxt) {}
}e[N*10];
int n,m,T,tot=1,top,ans,s[20],fir[N],val[N*5],p[N];
bool vis[N];
void Add_Edge(int u,int v) {
    e[++tot]=Edge(v,fir[u]), fir[u]=tot;
    e[++tot]=Edge(u,fir[v]), fir[v]=tot;
    return ;
}
void dfs1(int x,int from) {
    vis[x]=true;
    for(int i=fir[x];~i;i=e[i].nxt) {
        if(e[i].to==from) continue;
        if(!vis[e[i].to]) dfs1(e[i].to,x);
        else if(!val[i/2]) {
            int rd=RAND();
            val[i/2]=rd;
            p[x]^=rd;
            p[e[i].to]^=rd;
        }
    }
    return ;
}
void dfs2(int x,int from) {
    vis[x]=true;
    for(int i=fir[x];~i;i=e[i].nxt) {
        if(vis[e[i].to]) continue;
        dfs2(e[i].to,x);
        val[i/2]=p[e[i].to];
        p[x]^=p[e[i].to];
    }
    return ;
}
void Gauss() {
    int j=0;
    for(int k=30;~k;--k) {
        int i;
        for(i=j+1;i<=top;++i)
            if(s[i]&(1<<k))
                break;
        if(i==top+1) continue;
        swap(s[i],s[++j]);
        for(int i=1;i<=top;++i)
            if(s[i]&(1<<k) && i!=j)
                s[i]^=s[j];
    }
    return ;
}
int main() {
    memset(fir,-1,sizeof fir);
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<=m;++i) scanf("%d%d",&x,&y), Add_Edge(x,y);
    dfs1(1,0);
    memset(vis,false,sizeof vis);
    dfs2(1,0);
    for(scanf("%d",&T);T;--T) {
        scanf("%d",&top);
        for(int i=1;i<=top;++i) scanf("%d",s+i), s[i]=val[s[i]^ans];
        Gauss();
        if(s[top]) ++ans;
        puts(s[top] ? "Connected" : "Disconnected");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值