1. 程式人生 > >[差分][倍增lca][tarjan] Jzoj P3325 壓力

[差分][倍增lca][tarjan] Jzoj P3325 壓力

sizeof 多少 pri mat lds 解釋 必須 當前 const

Description

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

Input

第一行包含3個由空格隔開的正整數N,M,Q。
接下來M行,每行兩個整數u,v,表示第u個網絡設備(從1開始編號)和第v個網絡設備之間有一個鏈接。u不會等於v。兩個網絡設備之間可能有多個鏈接。
接下來Q行,每行兩個整數p,q,表示第p個網絡設備向第q個網絡設備發送了一個數據包。p不會等於q。

Output

輸出N行,每行1個整數,表示必須通過某個網絡設備的數據包的數量。

Sample Input

4 4 2
1 2
1 3
2 3
1 4
4 2
4 3

Sample Output

2
1
1
2
【樣例解釋】
設備1、2、3之間兩兩有鏈接,4只和1有鏈接。4想向2和3各發送一個數據包。顯然,這兩個數據包必須要經過它的起點、終點和1。

Data Constraint

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

題解

  • 題目大意:給出一個 N 個點,M 條邊的連通圖,和 M 個點對。詢問刪掉每個點會使 M 個點對中的幾個不連通
  • 其實就類似於求路徑上有多少個割點
  • 首先,可以tarjan求點雙分量,然後建新點,也就是縮點
  • 最後得到一顆樹
  • 然後就在樹上求兩點的lca
  • 最後就是差分了
  • 那麽怎麽做?
  • 將x,y點++,lca--,lca的父親--
  • 那麽怎麽處理在路徑上的割點呢?
  • 在倍增時,記錄對於新建點的父親
  • 那新建點也就是縮點後的點與父親只有一條路徑
  • 那麽就可以將父親的差分+當前點的差分,一步一步將樹向上加

代碼

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<vector>
 8 using namespace std;
 9 struct edge {int to,from; }e[200010*2],c[200010*2];
10 int n,m,q,dis,tot,cnt,num,cnt1,cnt2,head[200010],last[200010],dfn[100010],low[100010],k[100010],sh[200010],f[200010][21],dep[200010],d[200010];
11 void insert(int x,int y) { e[++cnt].to=y; e[cnt].from=head[x]; head[x]=cnt; }
12 void insert1(int x,int y) { c[++cnt2].to=y; c[cnt2].from=last[x]; last[x]=cnt2; }
13 void tarjan(int x)
14 {
15     dfn[x]=low[x]=++cnt1; k[++num]=x;
16     for (int i=head[x];i;i=e[i].from)
17     {
18         int v=e[i].to;
19         if (dfn[v]==-1)
20         {
21             tarjan(v);
22             low[x]=min(low[x],low[v]);
23             if (low[v]>=dfn[x])
24             {
25                 tot++;
26                 int j;
27                 do
28                 {
29                     j=k[num--]; 
30                     insert1(tot,j); insert1(j,tot);
31                 }
32                 while (j!=v);
33                 insert1(x,tot);insert1(tot,x);
34             }
35         }
36         else low[x]=min(low[x],dfn[v]);
37     }
38 }
39 void dfs(int x,int fa)
40 {
41     sh[sh[0]++]=x; f[x][0]=fa;
42     for (int i=1;i<=20;i++) f[x][i]=f[f[x][i-1]][i-1];
43     for (int i=last[x];i;i=c[i].from)
44     {
45         int v=c[i].to;
46         if (v==fa) continue;
47         dep[v]=dep[x]+1;
48         dfs(v,x);
49     }
50 }
51 int lca(int x,int y)
52 {
53     if (dep[x]>dep[y]) swap(x,y);
54     for (int i=20;i>=0;i--)
55         if (dep[f[y][i]]>=dep[x])
56             y=f[y][i];
57     if (x==y) return x;
58     for (int i=20;i>=0;i--)
59         if (f[x][i]!=f[y][i])
60             x=f[x][i],y=f[y][i];
61     return f[x][0];
62 }
63 int main()
64 {
65     scanf("%d%d%d",&n,&m,&q);
66     tot=n;
67     for (int i=1;i<=m;i++)
68     {
69         int u,v;    
70         scanf("%d%d",&u,&v);
71         insert(u,v); insert(v,u);
72     }
73     memset(dfn,-1,sizeof(dfn));
74     tarjan(1);
75     dep[1]=1; dfs(1,0);
76     for (int i=1;i<=q;i++)
77     {
78         int x,y;
79         scanf("%d%d",&x,&y);
80         dis=lca(x,y);
81         d[x]++; d[y]++; d[dis]--; d[f[dis][0]]--;
82     }
83     for (int i=tot;i>=1;i--) 
84     {
85         int now=sh[i];
86         d[f[now][0]]+=d[now];
87     }
88     for (int i=1;i<=n;i++) printf("%d\n",d[i]);
89     return 0;
90 }

[差分][倍增lca][tarjan] Jzoj P3325 壓力