loj2587 「APIO2018」铁人两项[圆方树+树形DP]
主要卡在一个结论上。。关于点双有一个常用结论,也经常作为在圆方树/简单路径上的良好性质,对于任意点双内互不相同的三点$s,c,t$,都存在简单路径$s\to c\to t$,证明不会。可以参见clz博客。。我就是跟着他学的
然后就好办了,转化为树上两点计经过点双内所有点个数,然后赋权后变为统计两两圆点对的路径权值和,这个就是一个树形DP,统计每个点作为圆点或者方点被所有路径经过多少次,加入答案。。
还是比较裸的,因为重点还在于这个很多题都出现到的点双的简单路径的性质。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #define mst(x) memset(x,0,sizeof x) 8 #define dbg(x) cerr << #x << " = " << x <<endl 9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl 10 using namespace std; 11 typedef long long ll; 12 typedef double db; 13 typedef pair<int,int> pii; 14 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 15 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;} 19 template<typename T>inline T read(T&x){ 20 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 21 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 22 } 23 const int N=1e5+7; 24 struct thxorz{ 25 int head[N<<1],nxt[N<<2],to[N<<2],tot; 26 inline void add(int x,int y){ 27 to[++tot]=y,nxt[tot]=head[x],head[x]=tot; 28 to[++tot]=x,nxt[tot]=head[y],head[y]=tot; 29 } 30 }G1,G2; 31 int n,m; 32 ll ans; 33 int val[N<<1],siz[N<<1],cnt,Siz; 34 int dfn[N],low[N],stk[N],top,tim; 35 #define y G1.to[j] 36 void tarjan(int x){ 37 dfn[x]=low[x]=++tim,stk[++top]=x,++Siz; 38 for(register int j=G1.head[x];j;j=G1.nxt[j]){ 39 if(!dfn[y]){ 40 tarjan(y),MIN(low[x],low[y]); 41 if(low[y]==dfn[x]){ 42 int tmp,sum=0;++cnt; 43 do tmp=stk[top--],G2.add(cnt,tmp),val[tmp]=-1,++sum;while(tmp^y); 44 G2.add(cnt,x),val[x]=-1;val[cnt]=++sum; 45 } 46 } 47 else MIN(low[x],dfn[y]); 48 } 49 } 50 #undef y 51 #define y G2.to[j] 52 void dp(int x,int fa){ 53 int d=x<=n;siz[x]=d; 54 for(register int j=G2.head[x];j;j=G2.nxt[j])if(y^fa){ 55 dp(y,x),siz[x]+=siz[y]; 56 ans+=siz[y]*1ll*(Siz-siz[y])*val[x]; 57 } 58 ans+=d*(Siz-1)*1ll*val[x]+(Siz-siz[x])*1ll*siz[x]*val[x]; 59 } 60 #undef y 61 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout); 62 read(n),read(m);cnt=n; 63 for(register int i=1,x,y;i<=m;++i)read(x),read(y),G1.add(x,y); 64 for(register int i=1;i<=n;++i)if(!dfn[i]){ 65 Siz=top=0;tarjan(i),dp(i,0); 66 } 67 printf("%lld\n",ans); 68 return 0; 69 }
总结:图上简单路径题多半和点双有关系