HDU 6350 Always Online
给出一个仙人掌,求
∑ s , t s ⊕ t ⊕ maxflow ( s , t ) \sum_{s,t}s \oplus t \oplus \operatorname{maxflow}(s,t) ∑s,ts⊕t⊕maxflow(s,t)
对于一棵树的情况, maxflow ( s , t ) \operatorname{maxflow}(s,t) maxflow(s,t)就是 s , t s,t s,t的简单路径上最短的一条边的权值。
用并查集从大到小枚举每条边,然后将边两端的点的集合合并,合并前可以通过统计每一位两边各有几个 0 / 1 0/1 0/1来维护题目需要的和。
对于仙人掌的情况,如果割了一条环上的边,那么就一定还需要割另一条环上的边,实际上是将每一个环分成了两个边的集合,两个集合各选最小的一条边删去。
那么环上最小权值的边一定会被删去,我们提前把环上权值最小的边删去后给环上的其他边加上这条边的权值,图就变成了一棵树,套用上述做法即可。
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define maxn 200005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL unsigned long long
using namespace std;
char cb[1<<16],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<16,stdin),cs==ct)?0:*cs++)
void read(int &res){
char ch;
for(;!isdigit(ch=getc()););
for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}
int n,m;
int sx[maxn],ty[maxn],cw[maxn],c[maxn];
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e=1;
void Node(int u,int v){
Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int dfn[maxn],low[maxn],sta[maxn],tot;
void trj(int u,int ff){
dfn[u] = low[u] = ++tot;
for(int i=info[u],v;i;i=Prev[i]) if(!dfn[v=to[i]]){
sta[++sta[0]] = i;
trj(v,u);
low[u] = min(low[u] , low[v]);
if(low[v] > dfn[u]){
for(int t=-1;to[t] != v;)
t = sta[sta[0]--];
}
if(low[v] == dfn[u]){
int loc = -1;
vector<int>G;
for(int t=-1;to[t] != v;){
t = sta[sta[0]--];
if(loc == -1 || cw[t / 2] < cw[loc])
loc = t / 2;
G.push_back(t / 2);
}
int val = cw[loc];
rep(j,0,G.size