LOJ2587:[APIO2018]铁人两项——题解
https://loj.ac/problem/2587#submit_code
(题面来自LOJ)
考试时候发觉树很可做,并且写了一个dp骗到了树的分。
苦于不会圆方树……现在回来发现这题还是很可做的!
先套路套圆方树,然后思考路径条数如何计算。
一个显然的想法:从一个点双-> 一个点双->……-> 一个点双,条数没准就是每个点双的大小!
于是我们能够想到方点的权值为点双的大小。
当然注意到我们选择的起点/终点以及每个点双之间相邻的切点只能走一次,为了去重,我们把圆点权值设为-1。
则任取起点s,终点t的情况就是s->t的路径上所有点的权值和。
当然此时我们可以用dp做,但是我当时的代码没拷于是现在我也忘了怎么做了,我们换一种大家普遍(我看其他人代码)的一种方法。
我们求出来每个点u,有多少条路径通过它即可,具体dp可以看我的代码注释。
以及注意这题每个结点之间至多有一条,而不是至少!坑死我了。
#include<cmath> #include<queue> #include<stack> #include<cstdio> #include<cctype> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N=2e5+5; const int M=N*2; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int u[M],v[M],nxt[M]; int cnt,head[N]; void init(){ cnt=0; memset(head,0,sizeof(head)); } void add(int U,int V){ u[++cnt]=U;v[cnt]=V;nxt[cnt]=head[U];head[U]=cnt; } }e,g; int n,m; int dfn[N],low[N],to[N],t,l; ll w[N]; stack<int>q; void tarjan(int u,int f){ dfn[u]=low[u]=++t; for(int i=g.head[u];i;i=g.nxt[i]){ int v=g.v[i]; if(!dfn[v]){ q.push(i); tarjan(v,u); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]){ int num;l++; do{ num=q.top();q.pop(); int uu=g.u[num],vv=g.v[num]; if(to[uu]!=l){ to[uu]=l; e.add(uu,l+n);e.add(l+n,uu); w[l+n]++;w[uu]=-1; } if(to[vv]!=l){ to[vv]=l; e.add(vv,l+n);e.add(l+n,vv); w[l+n]++;w[vv]=-1; } }while(num!=i); } }else if(low[u]>dfn[v]&&f!=v){ q.push(i); low[u]=dfn[v]; } } } bool vis[N]; ll ans,size[N],sum; void dfs1(int u,int f){ vis[u]=1; size[u]=(u<=n); for(int i=e.head[u];i;i=e.nxt[i]){ int v=e.v[i]; if(v==f)continue; dfs1(v,u); size[u]+=size[v]; } } void dfs2(int u,int f){ for(int i=e.head[u];i;i=e.nxt[i]){ int v=e.v[i]; if(v==f)continue; dfs2(v,u); ans+=w[u]*size[v]*(sum-size[v]); //以v根树为起点和以v根树补集为终点 //已经暗含了当u合法的时候,以u为终点的路径 } ans+=w[u]*(sum-size[u])*size[u]; //以u根树补集为起点和以u根树为终点 if(u<=n)ans+=w[u]*(sum-1);//以u为起点的路径 } int main(){ n=read(),m=read(); for(int i=1;i<=m;i++){ int u=read(),v=read(); g.add(u,v);g.add(v,u); } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i,0); for(int i=1;i<=n;i++){ if(!vis[i]){ dfs1(i,0);sum=size[i];dfs2(i,0); } } printf("%lld\n",ans); return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++