當前位置:
首頁 >
【APIO2018】Duathlon 铁人两项 【圆方树】
發(fā)布時間:2023/12/3
45
豆豆
生活随笔
收集整理的這篇文章主要介紹了
【APIO2018】Duathlon 铁人两项 【圆方树】
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
題意:給一張 nnn 點 mmm 邊的簡單無向圖,求有多少個三元組 (s,c,f)(s,c,f)(s,c,f) ,滿足存在一條從 sss 到 fff 經過 ccc 的簡單路徑。
n≤105,m≤2×105n\leq 10^5,m\leq 2\times 10^5n≤105,m≤2×105
首先這個 “經過 ccc 的簡單路徑” ,即 ccc 取所有 sss 到 fff 的簡單路徑的交集,就是能到達的所有點雙的并集,是圓方樹的標志。具體講解可以參考 PR的博客。
問題轉換成了:求所有點對路徑上的點雙的并集的大小 ?2-2?2 (起始點) 之和。
建出圓方樹,方點權值為其度數(shù) (即點雙的大小),圓點權值為 ?1-1?1 (點雙邊界的割點處被統(tǒng)計了兩次,需要減掉;起始點本來就要減掉)
這樣統(tǒng)計所有圓點路徑上的權值之和,就可以做到 O(n2)O(n^2)O(n2)
考慮每個結點的貢獻,計算子樹大小(方點不算大小)瞎算一下就可以 O(n)O(n)O(n)
因為我的板子比較奇怪,需要把邊去重,是 O(nlog?n)O(n\log n)O(nlogn) 的
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <vector> #include <algorithm> #define MAXN 100005 #define MAXM 400005 using namespace std; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } struct edge{int u,v;}e[MAXM]; int head[MAXN],nxt[MAXM],cnt=1; inline void addnode(int u,int v) {e[++cnt]=(edge){u,v};nxt[cnt]=head[u];head[u]=cnt; } int n,m; int dfn[MAXN],low[MAXN],tim; int stk[MAXM],tp,vis[MAXM],bcc[MAXM],vcnt; vector<int> rtt[MAXM]; void tarjan(int u) {dfn[u]=low[u]=++tim;for (int i=head[u];i;i=nxt[i]){if (!vis[i>>1]&&!bcc[i>>1]) vis[(stk[++tp]=i)>>1]=1;if (!dfn[e[i].v]){tarjan(e[i].v);low[u]=min(low[u],low[e[i].v]);if (dfn[u]==low[e[i].v]){rtt[u].push_back(++vcnt);rtt[vcnt].push_back(u);while (vis[i>>1]){int t=stk[tp--];vis[t>>1]=0;rtt[bcc[t>>1]=vcnt].push_back(e[t].v); // rtt[e[t].v].push_back(vcnt);}}}else low[u]=min(low[u],dfn[e[i].v]);} } int val[MAXM],siz[MAXM]; typedef long long ll; ll ans; void dfs(int u,int f,int tot) {siz[u]=(u<=n);vis[u]=1;for (int i=0;i<(int)rtt[u].size();i++){int v=rtt[u][i];if (v!=f){dfs(v,u,tot);ans+=(ll)siz[u]*siz[v]*val[u];siz[u]+=siz[v];}}ans+=(ll)siz[u]*(tot-siz[u])*val[u]; } int main() {n=read(),m=read();for (int i=1;i<=m;i++){int u,v;u=read(),v=read();addnode(u,v),addnode(v,u);}int las=0;vcnt=n;for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i),siz[i]=tim-las,las=tim;for (int i=1;i<=vcnt;i++){sort(rtt[i].begin(),rtt[i].end());rtt[i].erase(unique(rtt[i].begin(),rtt[i].end()),rtt[i].end());}for (int i=1;i<=n;i++) val[i]=-1;for (int i=n+1;i<=vcnt;i++) val[i]=(int)rtt[i].size();for (int i=1;i<=n;i++) if (!vis[i]) dfs(i,0,siz[i]);printf("%lld\n",2*ans);return 0; }總結
以上是生活随笔為你收集整理的【APIO2018】Duathlon 铁人两项 【圆方树】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux找不到文件或目录(linux找
- 下一篇: 【SDOI2018】战略游戏【圆方树】【