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 }
View Code

总结:图上简单路径题多半和点双有关系

posted @ 2019-10-30 09:50  Ametsuji_akiya  阅读(136)  评论(0编辑  收藏  举报