【BZOJ3331】[BeiJing2013]壓力 Tarjan求點雙
阿新 • • 發佈:2017-09-17
建立 getchar 路由器 小強 etc zoj ring inpu 數量
第一行包含3個由空格隔開的正整數N,M,Q。
接下來M行,每行兩個整數u,v,表示第u個網絡設備(從1開始編號)和第v個網絡設備之間有一個鏈接。u不會等於v。兩個網絡設備之間可能有多個鏈接。
接下來Q行,每行兩個整數p,q,表示第p個網絡設備向第q個網絡設備發送了一個數據包。p不會等於q。
1 2
1 3
2 3
1 4
4 2
4 3
1
1
2
【數據規模和約定】
對於40%的數據,N,M,Q≤2000
對於60%的數據,N,M,Q≤40000
對於100%的數據,N≤100000,M,Q≤200000
【BZOJ3331】[BeiJing2013]壓力
Description
如今,路由器和交換機構建起了互聯網的骨架。處在互聯網的骨幹位置的核心路由器典型的要處理100Gbit/s的網絡流量。他們每天都生活在巨大的壓力之下。 小強建立了一個模型。這世界上有N個網絡設備,他們之間有M個雙向的鏈接。這個世界是連通的。在一段時間裏,有Q個數據包要從一個網絡設備發送到另一個網絡設備。 一個網絡設備承受的壓力有多大呢?很顯然,這取決於Q個數據包各自走的路徑。不過,某些數據包無論走什麽路徑都不可避免的要通過某些網絡設備。 你要計算:對每個網絡設備,必須通過(包括起點、終點)他的數據包有多少個?Input
Output
輸出N行,每行1個整數,表示必須通過某個網絡設備的數據包的數量。Sample Input
4 4 21 2
1 3
2 3
1 4
4 2
4 3
Sample Output
21
1
2
HINT
【樣例解釋】
設備1、2、3之間兩兩有鏈接,4只和1有鏈接。4想向2和3各發送一個數據包。顯然,這兩個數據包必須要經過它的起點、終點和1。
對於40%的數據,N,M,Q≤2000
對於60%的數據,N,M,Q≤40000
對於100%的數據,N≤100000,M,Q≤200000
題解:顯然先用Tarjan求縮塊。。。怎麽求呢。。。基本功不紮實又去學了一發。
最後我們會得到一個樹形結構,但是。。。怎麽得到呢。。。其實對於每個塊新建一個點連向塊中的所有點即可。
然後就是一個類似於樹的東西了,怎麽統計樹上有哪些路徑必經一個點呢?差分即可。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int maxn=200010; int n,m,q,top,tot,sum,cnt; int sta[maxn],low[maxn],HEAD[maxn],NEXT[maxn<<1],TO[maxn<<1],head[maxn<<1],next[maxn<<2],to[maxn<<2]; int s[maxn<<1],fa[19][maxn<<1],Log[maxn<<1],dep[maxn<<1],Q[maxn<<1]; inline void ADD(int a,int b) { TO[cnt]=b,NEXT[cnt]=HEAD[a],HEAD[a]=cnt++; } inline void add(int a,int b) { to[cnt]=b,next[cnt]=head[a],head[a]=cnt++; } void tarjan(int x) { dep[x]=low[x]=++tot,sta[++top]=x; for(int y,i=HEAD[x],t;i!=-1;i=NEXT[i]) { y=TO[i]; if(!dep[y]) { tarjan(y),low[x]=min(low[x],low[y]); if(low[y]>=dep[x]) { sum++; do { t=sta[top--],add(sum,t),add(t,sum); }while(t!=y); add(sum,x),add(x,sum); } } else low[x]=min(low[x],dep[y]); } } void dfs(int x) { Q[++Q[0]]=x; for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[0][x]) fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]); } inline int lca(int a,int b) { int i; if(dep[a]<dep[b]) swap(a,b); for(i=Log[dep[a]-dep[b]];i>=0;i--) if(dep[fa[i][a]]>=dep[b]) a=fa[i][a]; if(a==b) return a; for(i=Log[dep[a]];i>=0;i--) if(fa[i][a]!=fa[i][b]) a=fa[i][a],b=fa[i][b]; return fa[0][a]; } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘)f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } int main() { //freopen("bz3331.in","r",stdin); n=rd(),m=rd(),q=rd(),sum=n; memset(head,-1,sizeof(head)),memset(HEAD,-1,sizeof(HEAD)); int i,j,a,b,c; for(i=1;i<=m;i++) a=rd(),b=rd(),ADD(a,b),ADD(b,a); cnt=0,tarjan(1),dep[1]=1,dfs(1); for(i=2;i<=sum;i++) Log[i]=Log[i>>1]+1; for(j=1;(1<<j)<=sum;j++) for(i=1;i<=sum;i++) fa[j][i]=fa[j-1][fa[j-1][i]]; for(i=1;i<=q;i++) { a=rd(),b=rd(),c=lca(a,b); s[a]++,s[b]++,s[c]--,s[fa[0][c]]--; } for(i=sum;i;i--) a=Q[i],s[fa[0][a]]+=s[a]; for(i=1;i<=n;i++) printf("%d\n",s[i]); return 0; }
【BZOJ3331】[BeiJing2013]壓力 Tarjan求點雙