BZOJ1315 : Ural1557Network Attack

找到一棵dfs搜索树,给每条非树边一个随机非0权值,每条树边为所有经过它的树边的权值的异或。

那么有2种情况是合法的:

1.一条边权值为0,一条边权值非0。

2.两条边异或和为0。

排序后统计即可,时间复杂度$O(m\log m)$。

 

#include<cstdio>
#include<algorithm>
const int N=2010,M=100010;
int n,m,i,j,e[M][2],g[N],v[M<<1],w[M<<1],nxt[M<<1],ed,d[N],dfn,f[N],c0,c1;
unsigned long long seed,h[M],tag[N],ans;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
  d[x]=++dfn;
  for(int i=g[x];i;i=nxt[i])if(w[i]!=f[x]){
    int y=v[i];
    if(d[y]&&d[y]<=d[x]){
      for(seed=seed*233+17;!seed;seed=seed*233+17);
      h[w[i]]=seed,tag[x]^=seed,tag[y]^=seed;
    }else if(!d[y])f[y]=w[i],dfs(y);
  }
}
void cal(int x){
  for(int i=g[x];i;i=nxt[i])if(f[v[i]]==w[i]&&d[v[i]]>d[x])cal(v[i]),tag[x]^=tag[v[i]];
  h[f[x]]=tag[x];
}
int main(){
  read(n),read(m);
  for(i=1;i<=m;i++)read(e[i][0]),read(e[i][1]),add(e[i][0],e[i][1],i),add(e[i][1],e[i][0],i);
  dfs(1),cal(1);
  for(i=1;i<=m;i++)if(h[i])c1++;else c0++;
  ans=1ULL*c0*c1;
  std::sort(h+1,h+m+1);
  for(i=1;i<=m;i=j){
    for(j=i;j<=m&&h[i]==h[j];j++);
    ans+=1ULL*(j-i)*(j-i-1)/2;
  }
  return printf("%llu",ans),0;
}

  

posted @ 2016-03-08 14:05  Claris  阅读(588)  评论(0编辑  收藏  举报