zoukankan      html  css  js  c++  java
  • dtoj#4222. 小b爱旅行(travel)

    题目描述:

    小 $b$ 有一张无向图。

    小 $b$ 可以从点 $1$ 出发,走任意一条路径,她将得到路径上的边的边权的异或值(一条边可能被经过多次,这时经过 几次就异或几次)。

    路径可以为空,这时异或值为 $0$ 。

    小 $b$ 想知道她能得到多少个不同的异或值。

    小 $b$ 还会删掉 $q$ 条边,每删一条边,她都会问你一次。

    数据范围:

    对于全部数据:

    $ullet~1 le n le 10^5,1 le m le 2 imes 10^5,0 le q le m$;

    $ullet~1 le x,y le n,0 le w le 10^{18}$;

    $ullet~1 le i le m$且所有 $i$ 互不相同;

    保证不存在重边和自环。

    对于 $10 \%$ 的数据,$m le 10$ 且 $q=0$ ;

    对于另外 $30 \%$ 的数据,$w le 1000$ 且 $q=0$ ;

    对于另外 $30 \%$ 的数据,$q=0$ 。

    算法标签:线性基

    思路:

    考虑对于一个环,是可以和任何一条路径异或得到的新的路径的。因为来回环上的点经过一次,来的路上经过的没有回路的路径,再回去的时候再走一次。

    所以我们把环挑出来断成链,变成一棵生成树,跑出这棵树上的答案,然后把环的答案存进线性基中。

    考虑如何把路径答案乘环的答案重复的时候,考虑对于线性基为1且路径答案为1的答案和对应为异或,最后得到的值互不相同,所有答案就会不相同。

    对于断链,我们把他反过来做,当成是不断加边,那么每次对于没有加到1联通块的不做修改,对于新加的与1相连的点,重新dfs,如果对线性基造成改变,就重新统计所有点的答案。

    效率是 $O(n imes3600 imes logn)$   这个 $log$ 是 $map$ 的 $log$ 改成 $hash$ 表就可以省去这个 $logn$ ,但是因为数据没跑满能过,就这样吧。

    以下代码:

    #include<bits/stdc++.h>
    #define il inline
    #define LL long long
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=1e5+5,M=4e5+5;
    bool pd,tag[M];
    LL w[M],dist[N],val[N],res[M],b[80],num;
    map<LL,bool> ma;
    int cnt,qr[M],tot;
    int n,m,q,head[N],ne[M],to[M],d[N],f[N];
    il LL read(){
        LL x;char ch;_(!);x=ch^48;
        _()x=(x<<1ll)+(x<<3ll)+(ch^48);
        return x;
    }
    il void ins(int x,int y,LL z){
        ne[++cnt]=head[x];head[x]=cnt;
        to[cnt]=y;w[cnt]=z;
    }
    il int getfa(int x){
        if(f[x]==x)return x;
        return f[x]=getfa(f[x]);
    }
    il void insert(LL x){
        for(int i=60;i>=0;i--){
            if(x&(1ll<<i)){
                if(b[i])x^=b[i];
                else{
                    b[i]=x;tot++;
                    pd=1;break;
                }
            }
        }
    }
    il void dfs1(int x,int fa){
        f[getfa(x)]=getfa(1);
        for(int i=head[x];i;i=ne[i]){
            if(fa==to[i]||tag[i])continue;
            if(!d[to[i]]){
                dist[to[i]]=dist[x]^w[i];
                d[to[i]]=d[x]+1;dfs1(to[i],x);
            }
            else{
                insert(dist[x]^dist[to[i]]^w[i]);
            }
        }
    }
    il LL C(LL x){
        for(int i=60;i>=0&&x;i--){
            if(b[i]&&(x>>i&1))x^=b[i];
        }
        return x;
    }
    il void add(int x){
        val[x]=C(dist[x]);
        if(!ma[val[x]])num++,ma[val[x]]=1;
    }
    il void dfs2(int x,int fa){
        f[getfa(x)]=getfa(1);add(x);
        for(int i=head[x];i;i=ne[i]){
            if(fa==to[i]||tag[i])continue;
            if(!d[to[i]]){
                dist[to[i]]=dist[x]^w[i];
                d[to[i]]=d[x]+1;
                dfs2(to[i],x);
            }
            else{
                insert(dist[x]^dist[to[i]]^w[i]);
            }
        }
    }
    il void rebuild(){
        num=0;
        for(int i=1;i<=n;i++)if(d[i])ma[val[i]]=0;
        for(int i=1;i<=n;i++)if(d[i])add(i);
    }
    int main()
    {
        n=read();m=read();q=read();
        for(int i=1;i<=n;i++)f[i]=i;
        for(int i=1;i<=m;i++){
            int x=read(),y=read();LL w=read();
            ins(x,y,w);ins(y,x,w);
        }
        for(int i=1;i<=q;i++){
            int x=read();qr[i]=x;
            tag[x<<1]=tag[(x<<1)-1]=1;
        }
        d[1]=1;dfs1(1,0);
        for(int i=1;i<=n;i++)if(d[i])add(i);
        for(int i=q;i;i--){
            res[i]=(1ll<<tot)*num;tag[qr[i]<<1]=tag[(qr[i]<<1)-1]=0;
            int a=to[qr[i]<<1],b=to[(qr[i]<<1)-1];
            int x=getfa(a),y=getfa(b);
            if(x==y){
                if(x^getfa(1))continue;
                pd=0;
                insert(dist[a]^dist[b]^w[qr[i]<<1]);
                if(pd)rebuild();
            }
            else{
                if(y==getfa(1))swap(x,y),swap(a,b);
                f[y]=x;
                if(x^getfa(1))continue;
                dist[b]=dist[a]^w[qr[i]<<1];
                pd=0;d[b]=d[a]+1;dfs2(b,a);
                if(pd)rebuild();
            }
        }
        res[0]=(1ll<<tot)*num;
        for(int i=0;i<=q;i++)printf("%lld
    ",res[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    《图解算法》读书笔记(十)K最近邻算法
    《图解算法》读书笔记(九) 动态规划
    《图解算法》读书笔记(八) 贪婪算法
    Go 常用包之fmt、flag包(四)
    GO环境及初始化项目(二)
    nginx fpm 常见错误对比分析
    Ueditor富文本添加、编辑视频,视频不显示解决方案
    phpunit 测试
    mysql 主从并行复制(MTS)
    Explain执行计划详解
  • 原文地址:https://www.cnblogs.com/Jessie-/p/10454416.html
Copyright © 2011-2022 走看看