[APIO2018] Duathlon 铁人两项
求有多少个三元组 ( s , c , f ) (s,c,f) (s,c,f)满足 s , c , f s,c,f s,c,f互不相同,而且在给定的图上存在一条从 s s s经过 c c c到达 t t t的简单路径。
建出圆方树,两个圆点 s , f s,f s,f可以选择的 c c c为路径中所有的点双中的点,定义方点的权值为其所代表的点双的点数,圆点的权值为 − 1 -1 −1,那么两个圆点可以选择的点数就是路径上的权值和(因为 s s s和 f f f是圆点,所以 c = s c=s c=s或 t t t的情况是被减去了的),反过来 d p dp dp每个点被多少条路径覆盖即可。
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 pb push_back
#define LL 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,tot;
vector<int>G[maxn],E[maxn];
int dfn[maxn],low[maxn],tim,sta[maxn],tp;
void dfs(int u,int ff){
dfn[u] = low[u] = ++tim;
sta[++tp] = u;
for(int i=0,v;i<G[u].size();i++) if(!dfn[v=G[u][i]]){
dfs(v,u),low[u]=min(low[u],low[v]);
if(low[v] >= dfn[u]){
++tot;
for(int t=-1;t!=v;){
E[t=sta[tp--]].pb(tot),
E[tot].pb(t);
}
E[tot].pb(u) , E[u].pb(tot);
}
}else if(v != ff) low[u] = min(low[u] , dfn[v]);
}
bool vis[maxn];
LL ans;
int f[maxn];
void dfs2(int u,int ff){
vis[u] = 1;
f[u] = (u <= n);
for(int i=0,v;i<E[u].size();i++) if((v=E[u][i]) ^ ff){
dfs2(v,u);
ans += 1ll * f[v] * f[u] * (u <= n ? -1ll : E[u].size());
f[u] += f[v];
}
}
void dfs3(int u,int ff,int tsz){
ans += 1ll * f[u] * (tsz-f[u]) * (u <= n ? -1ll : E[u].size());
for(int i=0,v;i<E[u].size();i++) if((v=E[u][i]) ^ ff)
dfs3(v,u,tsz);
}
int main(){
read(n),read(m);
rep(i,1,m){
int u,v;read(u),read(v);
G[u].pb(v),G[v].pb(u);
}
tot = n;
rep(i,1,n) if(!dfn[i]) dfs(i,0);
rep(i,1,tot) if(!vis[i]){
dfs2(i,0);
dfs3(i,0,f[i]);
}
printf("%lld\n",ans << 1);
}
「POI2011 R2 Day1」垃圾运输 Garbage
无向图每条边非黑即白,求出若干个简单环使得依次将每个环上的所有边颜色取反后所有边的颜色都为目标颜色。
这题放圆方树是什么意思啊。
发现对于不用取反的边,如果有环经过,那么会有偶数个环经过,可以将这两个环合并为一个大环,具体是只保留经过了奇数次的边。
所以就是对需要取反的边求简单环覆盖。
判无解就判可不可以有多个欧拉回路即可。
所以这个题就是求欧拉回路,把回路分解成若干个简单环即可。
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define maxm 2000005
using namespace std;
int n,m;
int in[maxm];
int info[maxm],Prev[maxm],to[maxm],cnt_e=1;
void Node(int u,int v){
Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int ans[maxm],K,tp,L[maxm],R[maxm],ed[maxm];
void dfs(int u,int hd=1){
for(int &i=info[u],v;i;i=Prev[i]) if((v=to[i]))
to[i]=to[i^1]=0,dfs(v),hd=1;
if(hd) ans[++tp] = u;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,a,b,s,t;i<=m;i++){
scanf("%d%d%d%d",&a,&b,&s,&t);
if(s ^ t) Node(a,b),Node(b,a),in[a]++,in[b]++;
}
for(int i=1;i<=n;i++) if(in[i]&1) return puts("NIE"),0;
for(int i=1;i<=n;i++) dfs(i,0) , ed[tp] = 1;
int pr=1;
for(int i=2;i<=tp;i++) if(ans[i] == ans[pr]){
L[++K] = pr , R[K] = i;
i += ed[i];
pr = i;
}
printf("%d\n",K);
for(int i=1;i<=K;i++){
printf("%d ",R[i]-L[i]);
for(int j=L[i];j<=R[i];j++)
printf("%d%c",ans[j]," \n"[j==R[i]]);
}
}
【CF Round #278】Tourists
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
int n,m,q;
int info[maxn],Prev[maxn],to[maxn],cnt_e;
void Node(int u,int v){
Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int w[maxn],tot;
vector<int>G[maxn];
int dfn[maxn],low[maxn],dfsn;
int vis[maxn];
stack<pair<int,int> >sta;
void dfs(int now,int ff){
dfn[now] = low[now] = ++dfsn;
for(int i=info[now];i;i=Prev[i])
if(!dfn[to[i]]){
sta.push(make_pair(now,to[i]));
dfs(to[i],now);
low[now] = min(low[now] , low[to[i]]);
if(low[to[i]] >= dfn[now]){
++tot;
for(;!sta.empty();){
int u=sta.top().first,v=sta.top().second;sta.pop();
if(vis[u] < tot) vis[u] = tot , G[tot].push_back(u) , G[u].push_back(tot);
if(vis[v] < tot) vis[v] = tot , G[tot].push_back(v) , G[v].push_back(tot);
if(u == now && v == to[i]) break;
}
}
}
else low[now]=min(low[now],dfn[to[i]]);
}
int siz[maxn],son[maxn],dep[maxn],fa[maxn],tp[maxn],id[maxn],pos[maxn],cnt;
void dfs2(int now,int ff){
siz[now] = 1 , son[now] = -1 , dep[now] = dep[fa[now] = ff] + 1;
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if((v=G[now][i])!=ff){
dfs2(v,now);
siz[now] += siz[v];
if(son[now] == -1 || siz[son[now]] < siz[v])
son[now] = v;
}
}
void dfs3(int now,int ff){
pos[id[now] = ++cnt] = now;
if(son[now]!=-1) tp[son[now]]=tp[now],dfs3(son[now],now);
for(int i=0,sz=G[now].size(),v;i<sz;i++)
if((v=G[now][i])!=ff && v!=son[now]){
tp[v] = v;
dfs3(v,now);
}
}
multiset<int>st[maxn];
#define lc now << 1
#define rc now << 1 | 1
int Min[maxn<<3];
void upd(int now){
Min[now] = min(Min[lc],Min[rc]); }
void Build(int now,int l,int r){
if(l == r){
Min[now]=(pos[l]<=n?