1. 程式人生 > >bzoj3331 [BeiJing2013]壓力 圓方樹+樹上差分

bzoj3331 [BeiJing2013]壓力 圓方樹+樹上差分

Description


如今,路由器和交換機構建起了網際網路的骨架。處在網際網路的骨幹位置的
核心路由器典型的要處理100Gbit/s的網路流量。他們每天都生活在巨大的壓力
之下。
小強建立了一個模型。這世界上有N個網路裝置,他們之間有M個雙向的
連結。這個世界是連通的。在一段時間裡,有Q個數據包要從一個網路裝置發
送到另一個網路裝置。
一個網路裝置承受的壓力有多大呢?很顯然,這取決於Q個數據包各自走
的路徑。不過,某些資料包無論走什麼路徑都不可避免的要通過某些網路設
備。
你要計算:對每個網路裝置,必須通過(包括起點、終點)他的資料包有
多少個?

對於40%的資料,N,M,Q≤2000
對於60%的資料,N,M,Q≤40000
對於100%的資料,N≤100000,M,Q≤200000

Solution


一開始寫了縮點發現這樣不太好做。。
考慮建廣義圓方樹,路徑上的必經點顯然是樹上路徑中的圓點
由於做了很多天的樹鏈剖分模擬賽已經吐了,我們今天用差分的做法。
對於一條路徑修改(x,y),我們在x、y處+1,在lca和fa[lca]處-1,然後離線求和即可
好像沒啥好說的。。。

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stack>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x)) const int N=200005; std:: stack <int> stack; struct Graph { struct edge {int y,next;} e[N*2]; int ls[N],edCnt; Graph() {fill(ls,0); edCnt=1;} edge operator [](int x) const { return e[x]; } void add_edge(int x,int y) { e[++edCnt]=(edge) {y,ls[x]
}; ls[x]=edCnt; e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt; } } G,T; int bl[N],size[N],fa[N],dep[N]; int dfn[N],low[N]; int s[N],tot; bool vis[N]; int read() { int x=0,v=1; char ch=getchar(); for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar()); for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar()); return x*v; } void dfs(int now,int from) { dfn[now]=low[now]=++dfn[0]; vis[now]=true; for (int i=G.ls[now];i;i=G[i].next) { if ((i^1)==from) continue; if (!dfn[G[i].y]) { stack.push(i); dfs(G[i].y,i); low[now]=std:: min(low[now],low[G[i].y]); if (dfn[now]<=low[G[i].y]) { int y=0; tot++; while (y!=i) { y=stack.top(); stack.pop(); T.add_edge(tot,G[y].y); } T.add_edge(now,tot); } } else if (vis[G[i].y]) low[now]=std:: min(low[now],dfn[G[i].y]); } vis[now]=false; } void dfs1(int now) { size[now]=1; for (int i=T.ls[now];i;i=T[i].next) { if (T[i].y==fa[now]) continue; fa[T[i].y]=now; dep[T[i].y]=dep[now]+1; dfs1(T[i].y); size[now]+=size[T[i].y]; } } void dfs2(int now,int up) { bl[now]=up; int mx=0; for (int i=T.ls[now];i;i=T[i].next) { if (T[i].y!=fa[now]&&size[T[i].y]>size[mx]) mx=T[i].y; } if (!mx) return ; dfs2(mx,up); for (int i=T.ls[now];i;i=T[i].next) { if (T[i].y!=fa[now]&&T[i].y!=mx) dfs2(T[i].y,T[i].y); } } int get_lca(int x,int y) { for (;bl[x]!=bl[y];) { (dep[bl[x]]<dep[bl[y]])?(std:: swap(x,y)):(void)0; x=fa[bl[x]]; } return dep[x]<dep[y]?x:y; } void dfs3(int now) { for (int i=T.ls[now];i;i=T[i].next) { if (T[i].y==fa[now]) continue; dfs3(T[i].y); s[now]+=s[T[i].y]; } } int main(void) { int n=read(),m=read(),q=read(); tot=n; rep(i,1,m) G.add_edge(read(),read()); dfs(1,0); dfs1(1); dfs2(1,1); rep(i,1,q) { int x=read(),y=read(); int lca=get_lca(x,y); s[x]++; s[y]++; s[lca]--; s[fa[lca]]--; } dfs3(1); rep(i,1,n) printf("%d\n", s[i]); return 0; }