【日常小测】CDC分治

  • 本文为博主原创,未经许可不得转载

首先我们注意到所有的必达点一定不在环上,或者是环上的割点,所以我们用BCC算法将图缩成树

至于在树上求这个东西,需要大力推一波公式,具体参考特教的理性愉悦一题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include<bits/stdc++.h>
#define FILE "read"
#define MAXN (int)2e6+5
#define cmin(a,b) a=min(a,b)
#define cmax(a,b) a=max(a,b)
using namespace std;
typedef long long ll;
struct node{int y,next;}e[MAXN<<1];
int n,m,Q,cnt,len,top,bcnt,dfs_clock,sta[MAXN],Link[MAXN],deep[MAXN],dfn[MAXN],low[MAXN],anc[MAXN][25];
ll ans,v[MAXN],sumv[MAXN],sumvd[MAXN],sumvdd[MAXN];
vector<int>bcc[MAXN];
inline int read(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
void insert(int x,int y){
e[++len].next=Link[x];Link[x]=len;e[len].y=y;
e[++len].next=Link[y];Link[y]=len;e[len].y=x;
}
void tarjan(int x){
dfn[x]=low[x]=++dfs_clock; sta[++top]=x;
for(int i=Link[x];i;i=e[i].next)if(!dfn[e[i].y]){
tarjan(e[i].y); cmin(low[x],low[e[i].y]);
if(low[e[i].y]>=dfn[x]){
bcnt++; int y;
do{
y=sta[top--];
bcc[bcnt].push_back(y);
}while(y!=e[i].y);
bcc[bcnt].push_back(x);
}
}else cmin(low[x],dfn[e[i].y]);
}
void dfs(int x,int fa){
int flag=0;
for(int i=Link[x];i;i=e[i].next)if(e[i].y!=fa&&e[i].y){
deep[e[i].y]=deep[x]+1; anc[e[i].y][0]=x;
sumv[e[i].y]=sumv[x]+v[e[i].y];
sumvd[e[i].y]=sumvd[x]+v[e[i].y]*deep[e[i].y];
sumvdd[e[i].y]=sumvdd[x]+v[e[i].y]*deep[e[i].y]*deep[e[i].y];
dfs(e[i].y,x); flag=1;
}
if(!flag){//叶子结点则新建方点
insert(x,++cnt); deep[cnt]=deep[x]+1; anc[cnt][0]=x;
sumv[cnt]=sumv[x]; sumvd[cnt]=sumvd[x]; sumvdd[cnt]=sumvdd[x];
}
}
int LCA(int x,int y){
if(deep[x]<deep[y]) swap(x,y);
for(int i=20;i>=0;--i) if(deep[anc[x][i]]>=deep[y]) x=anc[x][i];
if(x==y) return x;
for(int i=20;i>=0;--i) if(anc[x][i]!=anc[y][i]) x=anc[x][i],y=anc[y][i];
return anc[x][0];
}
ll get(int x,int lca,int k){
ll temp1=(sumv[x]-sumv[lca])*(k-deep[lca])*(deep[x]+1);
ll temp2=(sumvd[x]-sumvd[lca])*(deep[x]+1-k+deep[lca]);
ll temp3=sumvdd[x]-sumvdd[lca];
return temp1+temp2-temp3;
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
int __size__=256<<20;
char *__p__=(char*)malloc(__size__)+__size__;
__asm__("movl %0, %%esp\n"::"r"(__p__));
n=cnt=read(); m=read(); Q=read(); deep[1]=1;
for(int i=1;i<=n;++i) v[i]=read();
for(int i=1;i<=m;++i){int x=read(),y=read();insert(x,y);}
tarjan(1); memset(Link,0,sizeof(Link)); len=0;
for(int i=1;i<=bcnt;++i){
++cnt; int size=bcc[i].size();
for(int j=size-1;j>=0;--j)
insert(cnt,bcc[i][j]);
}
sumv[1]=sumvd[1]=sumvdd[1]=v[1];
dfs(1,0); anc[1][0]=++cnt;
for(int i=1;i<=20;++i)for(int x=1;x<=cnt;++x)
anc[x][i]=anc[anc[x][i-1]][i-1];
for(int T=1;T<=Q;++T){
int x=read(),y=read(),lca=LCA(x,y);
if(x==lca) x=anc[x][0];
else{
for(int i=Link[x];i;i=e[i].next)if(e[i].y!=anc[x][0]&&e[i].y){x=e[i].y;break;}
}
if(y==lca) y=anc[y][0];
else{
for(int i=Link[y];i;i=e[i].next)if(e[i].y!=anc[y][0]&&e[i].y){y=e[i].y;break;}
}
lca=LCA(x,y);
int k1=deep[y]-deep[lca]+1,k2=deep[x]-deep[lca]+1;
ans=get(x,lca,k1)+get(y,lca,k2)+v[lca]*k1*k2;
printf("%lld\n",ans>>2);
}
return 0;
}
文章目录
,