dtoj#4222. 小b爱旅行(travel)
Posted jessie-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
以上是关于dtoj#4222. 小b爱旅行(travel)的主要内容,如果未能解决你的问题,请参考以下文章
MIP经典问题:旅行商问题 (traveling salesman problem)