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

Posted comfortable

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[差分][倍增lca][tarjan] Jzoj P3325 压力相关的知识,希望对你有一定的参考价值。

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
",d[i]);
89     return 0;
90 }

 

以上是关于[差分][倍增lca][tarjan] Jzoj P3325 压力的主要内容,如果未能解决你的问题,请参考以下文章

LCA[倍增][树剖][tarjan]

LCA (Tarjan&倍增)

倍增 Tarjan 求LCA

LCA算法解析-Tarjan&倍增

两种lca的求法:树上倍增,tarjan

[Nowcoder] network | Tarjan 边双连通分量 | 缩点 | LCA倍增优化 | 并查集