题干:
这世界上有N个网络设备,他们之间有M个双向的链接。这个世界是连通的。在一段时间里,有Q个数据包要从一个网络设备发送到另一个网络设备。一个网络设备承受的压力有多大呢?很显然,这取决于Q个数据包各自走的路径。不过,某些数据包无论走什么路径都不可避免的要通过某些网络设备。你要计算:对每个网络设备,必须通过(包括起点、终点)他的数据包有多少个?
对于40%的数据,N,M,Q≤2000
对于60%的数据,N,M,Q≤40000
对于100%的数据,N≤100000,M,Q≤200000
题解:
必须通过的路径?很容易就可以想到树上差分求解(在路径上都放一个价值为1的物品,答案就是每个点物品的总价值)。
但题干中并没有说这一定是一棵树,只是说是连通图。
那我们就需考虑几种情况:
1、起始节点与末尾节点都为割点:直接在起始节点与末尾节点差分
(怎么来的割点?不是走路径吗?其实我们差分的对象是几个点,针对于点,我们就应该想到点双连通分量)
2、起始节点与末尾节点有一个不为割点或都不为割点:
这就需要先找出起始节点或末尾节点所在环的割点,再在这个割点上进行差分。
(直接差分不行吗?题干中说的是“ 必须通过它的数据包有多少个 ”,若一个点在环上,那么它一定至少有两条路径可以走,就不满足“ 必须 ”这个条件)
考虑了这两种情况,这道题就有了一个比较完整的框架。但在真正解题时,我们采用缩点的方法来等效于上述
“找出起始节点或末尾节点所在环的割点,再在这个割点上进行差分”
(在最后的统计答案中,dfs序还是比较好用,省去了跑dfs统计答案)
tarjan 点双连通分量求法+缩点:
1 if(!dfn[to]){ 2 tarjan(to); 3 low[x]=min(low[x],low[to]); 4 if(low[to]>=dfn[x]){ 5 opt++; sum++; 6 if(x!=1||opt>1) cut[x]=1; 7 do{ 8 tmp=sta[up--]; 9 cir[tmp]=sum; 10 dcc[sum].push_back(tmp); 11 }while(tmp!=to); 12 cir[x]=sum; 13 dcc[sum].push_back(x); 14 } 15 } 16 else low[x]=min(low[x],dfn[to]);
Code:(两种不同打法,第二种为正解,第一种打得较方便,但时间复杂度会高一些)
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<iostream> 5 #define $ 220010 6 using namespace std; 7 int m,n,q,first[$],tot1,dfn[$],low[$],tar,tip[$],second[$],tot2; 8 int dad[$][22],sta[$],up,ans[$],dep[$],sum,pre[$]; 9 struct tree{ int to,next; }a[$*5],tr[$*5]; 10 inline int min(int x,int y) { return x<y?x:y; } 11 inline void swap(int &x,int &y){ int t=x; x=y; y=t; } 12 inline void add(int x,int y){ 13 a[++tot1]=(tree){ y,first[x] }; 14 first[x]=tot1; 15 a[++tot1]=(tree){ x,first[y] }; 16 first[y]=tot1; 17 } 18 inline void addtr(int x,int y){ 19 tr[++tot2]=(tree){ y,second[x] }; 20 second[x]=tot2; 21 tr[++tot2]=(tree){ x,second[y] }; 22 second[y]=tot2; 23 } 24 inline void tarjan(int x){ 25 dfn[x]=low[x]=++tar; sta[++up]=x; 26 for(register int i=first[x],tmp;i;i=a[i].next){ 27 int to=a[i].to; 28 if(!dfn[to]){ 29 tarjan(to); 30 low[x]=min(low[x],low[to]); 31 if(low[to]>=dfn[x]){ 32 ++sum; 33 do{ 34 tmp=sta[up--]; 35 addtr(sum,tmp); 36 }while(tmp!=to); 37 addtr(sum,x); 38 } 39 } 40 else low[x]=min(low[x],dfn[to]); 41 } 42 } 43 inline void ready(int x){ 44 pre[--pre[0]]=x; 45 for(register int i=second[x];i;i=tr[i].next){ 46 int to=tr[i].to; 47 if(to==dad[x][0]) continue; 48 dad[to][0]=x; 49 for(register int j=1;j<=20;++j) dad[to][j]=dad[dad[to][j-1]][j-1]; 50 dep[to]=dep[x]+1; 51 ready(to); 52 } 53 } 54 inline int LCA(int x,int y){ 55 if(dep[x]<dep[y]) swap(x,y); 56 for(register int i=20;i>=0;--i) 57 if(dep[dad[x][i]]>=dep[y]) x=dad[x][i]; 58 if(x==y) return x; 59 for(register int i=20;i>=0;--i) 60 if(dad[x][i]!=dad[y][i]) x=dad[x][i],y=dad[y][i]; 61 return dad[x][0]; 62 } 63 signed main(){ 64 scanf("%d%d%d",&n,&m,&q); sum=n; 65 for(register int i=1,x,y;i<=m;++i) scanf("%d%d",&x,&y),add(x,y); 66 tarjan(1); 67 pre[0]=sum+1; dep[1]=1; 68 ready(1); 69 for(register int i=1,x,y,lca;i<=q;++i){ 70 scanf("%d%d",&x,&y); lca=LCA(x,y); 71 ++ans[x]; ++ans[y]; 72 --ans[lca]; --ans[dad[lca][0]]; 73 } 74 for(register int i=1,x;i<=sum;++i) 75 x=pre[i],ans[dad[x][0]]+=ans[x]; 76 for(register int i=1;i<=n;++i) printf("%d\n",ans[i]); 77 }
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<vector> 5 #define $ 220010 6 using namespace std; 7 int m,n,q,first[$],tot1,dfn[$],low[$],tar,tip[$],second[$],tot2,cut[$],cnt; 8 int dad[$*2][22],sta[$],up,ans[$],dep[$],sum,pre[$],cir[$],id[$],data[$]; 9 vector<int> dcc[$]; 10 struct tree{ int to,next; }a[$*5],tr[$*5]; 11 inline int min(int x,int y) { return x<y?x:y; } 12 inline void swap(int &x,int &y){ int t=x; x=y; y=t; } 13 inline void add(int x,int y){ 14 a[++tot1]=(tree){ y,first[x] }; 15 first[x]=tot1; 16 a[++tot1]=(tree){ x,first[y] }; 17 first[y]=tot1; 18 } 19 inline void addtr(int x,int y){ 20 tr[++tot2]=(tree){ y,second[x] }; 21 second[x]=tot2; 22 tr[++tot2]=(tree){ x,second[y] }; 23 second[y]=tot2; 24 } 25 inline void tarjan(int x,int opt=0){ 26 dfn[x]=low[x]=++tar; sta[++up]=x; 27 for(register int i=first[x],tmp;i;i=a[i].next){ 28 int to=a[i].to; 29 if(!dfn[to]){ 30 tarjan(to); 31 low[x]=min(low[x],low[to]); 32 if(low[to]>=dfn[x]){ 33 opt++; sum++; 34 if(x!=1||opt>1) cut[x]=1; 35 do{ 36 tmp=sta[up--]; 37 cir[tmp]=sum; 38 dcc[sum].push_back(tmp); 39 }while(tmp!=to); 40 cir[x]=sum; 41 dcc[sum].push_back(x); 42 } 43 } 44 else low[x]=min(low[x],dfn[to]); 45 } 46 } 47 inline void ready(int x){ 48 pre[--pre[0]]=x; 49 for(register int i=second[x];i;i=tr[i].next){ 50 int to=tr[i].to; 51 if(to==dad[x][0]) continue; 52 dad[to][0]=x; 53 for(register int j=1;j<=20;++j) dad[to][j]=dad[dad[to][j-1]][j-1]; 54 dep[to]=dep[x]+1; 55 ready(to); 56 } 57 } 58 inline int LCA(int x,int y){ 59 if(dep[x]<dep[y]) swap(x,y); 60 for(register int i=20;i>=0;--i) 61 if(dep[dad[x][i]]>=dep[y]) x=dad[x][i]; 62 if(x==y) return x; 63 for(register int i=20;i>=0;--i) 64 if(dad[x][i]!=dad[y][i]) x=dad[x][i],y=dad[y][i]; 65 return dad[x][0]; 66 } 67 signed main(){ 68 scanf("%d%d%d",&n,&m,&q); cnt=n; 69 for(register int i=1,x,y;i<=m;++i) scanf("%d%d",&x,&y),add(x,y); 70 tarjan(1); 71 for(register int i=1;i<=n;++i) if(cut[i]) cir[i]=id[i]=++cnt; 72 for(register int i=1;i<=sum;++i) 73 for(register int j=0;j<dcc[i].size();++j){ 74 int to=dcc[i][j]; 75 if(cut[to]) addtr(i,id[to]); 76 } 77 pre[0]=cnt+1; dep[1]=1; 78 ready(1); 79 for(register int i=1,x,y,lca;i<=q;++i){ 80 scanf("%d%d",&x,&y); 81 if(!cut[x]) data[x]++; 82 if(!cut[y]) data[y]++; 83 x=cir[x], y=cir[y]; 84 lca=LCA(x,y); 85 ++ans[x]; ++ans[y]; 86 --ans[lca]; --ans[dad[lca][0]]; 87 } 88 for(register int i=1,x;i<=cnt;++i) 89 x=pre[i],ans[dad[x][0]]+=ans[x]; 90 for(register int i=1;i<=n;++i) printf("%d\n",cut[i]?ans[cir[i]]:data[i]); 91 }
原文地址:https://www.cnblogs.com/OI-zzyy/p/11183044.html