51nod2614 小B爱旅行 (参考范艺杰代码 基本抄袭 太难了)

在这里插入图片描述
由题意可知 图是由 环 和 直链组成的 若 环能到达 那么 能到达的直链 都能和环组成 一组数 因为 每个到达环的路径再回来 把到环上的直链抵消了
所以我们 可以考虑 把环上的值全都扔进线性基 再看直链上有哪些值是能和环组成新值的
如果 线性基里能组成的 那么链上的就无需加入 若不能组成的 那么 一定会有一位 是线性基里所没有的那么答案就是 (1<<sz) * s.size() s表示线性基组成不了的数的个数 sz表示线性基里的元素个数

2.删边我们可以考虑离线从后往前加边 若加的边多环 那么重组一下线性基 并且重组一下 s.size() 若没有影响 就先存着 防止后面会用上 复杂度为 60nlogn

#include<iostream>
#include<cstring>
#include<set>
#include<vector>

using namespace std;

const int N = 2e5 + 10,M = N * 8;
typedef long long ll;

int head[N],to[M],last[M];ll w[M],cnt;
void add(int a,int b,ll c){
    to[++cnt] = b;
    w[cnt] = c;
    last[cnt] = head[a];
    head[a] = cnt;
}

int flag[N],id[N],fa[N],x[N],y[N];ll z[N];
int get(int x){
    if(fa[x] == x) return x;
    return fa[x] = get(fa[x]);
}

int n,m,q;
set<ll>s;
vector<int>R[N];

ll dis[N],p[N],ans[N];
ll dt(ll x){
    for(int i = 60; i >= 0; i--){
        if((x & (1ll << i)) && p[i]) x ^= p[i];
    }
    return x;
}

void dfs(int x,int lastt){
    s.insert(dt(dis[x]));
    for(int i = head[x]; i != -1; i = last[i]){
        int j = to[i];
        if(j == lastt) continue;
        dis[j] = dis[x] ^ w[i];
        dfs(j,x);
    }
}

ll sz;
bool insert(ll x){
    for(int i = 60; i >= 0; i--){
        if(x & (1ll << i)){
            if(p[i]){
                x ^= p[i];
            }else{
                p[i] = x;
                sz++;
                return true;
            }
        }
    }
    return false;
}

void build(){
    set<ll>S;
    for(auto it = s.begin(); it != s.end(); it++) S.insert(dt(*it));
    swap(S,s);
}


int main() {
    for(int i = 0; i <= 2e5; i++) fa[i] = i,head[i] = -1;
    cin >> n >> m >> q;
    for(int i = 1; i <= m; i++){
        scanf("%d%d%lld",&x[i],&y[i],&z[i]);
    }
    for(int i = 1; i <= q; i++){
        scanf("%d",&id[i]);
        flag[id[i]] = 1;
    }

    for(int i = 1; i <= m; i++){
        if(flag[i]) continue;
        if(get(x[i]) != get(y[i])){
            add(x[i],y[i],z[i]);
            add(y[i],x[i],z[i]);
            fa[get(x[i])] = get(y[i]);
        }
    }

    s.insert(0);
    dfs(1,0);

    for(int i = 1; i <= m; i++){
        if(flag[i]) continue;
        if(get(x[i]) == get(1)) insert(dis[x[i]] ^ dis[y[i]] ^ z[i]); // 环
        else R[get(x[i])].push_back(i);
    }

    build();
    ans[q + 1] = (1ll << sz) * s.size();

    for(int i = q; i >= 1; i--){
        ll u = x[id[i]],v = y[id[i]],ww = z[id[i]];
        if(get(u) == get(v)){ //环
            if(get(u) == get(1)){ //和1有关的环
                if(insert(dis[u] ^ dis[v] ^ ww)) build();
            }else R[get(u)].push_back(id[i]); //后面添边可能 出现与1相关的新环
        }else{
            if(get(u) == get(1) || get(v) == get(1)){
                if(get(v) == get(1)) swap(u,v);
                dis[v] = dis[u] ^ ww; //图变了 可能有新环 或者值
                add(u,v,ww);
                dfs(v,u);
                bool st = false;
                for(int i : R[get(v)]){
                    if(insert(dis[x[i]] ^ dis[y[i]] ^ z[i])) st = true;
                }
                if(st) build();
                fa[get(u)] = get(v);
            }else{
                add(u,v,ww);
                add(v,u,ww);
                u = get(u),v = get(v);
                if(R[u].size() > R[v].size()) swap(u,v);
                for(int x : R[u]) R[v].push_back(x);
                fa[u] = v;
            }
        }
        ans[i] = (1ll << sz) * s.size();
    }

    for(int i = 1; i <= q + 1; i++) cout <<ans[i] << endl;



	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值