题解:P10304 [THUWC 2020] 道路修建
题目
给定
思路
首先按照规则生成树,记录节点深度
由于原图是 DAG,发现非树边只能是前向边或横叉边。定义
对于非树边
然后将所有询问按被断开的最浅深度
需要统计
- 连通块合并:节点
x 变白时,将其自身及下方的白块打包,利用并查集向上寻找第一个存活的黑点祖先p 。 - 树上差分:设上浮白块大小为
s ,在树状数组中执行单点修改,即在dfn_x 处加s ,dfn_p 处减s 。 - 区间查询:处理完当前深度的所有断联点后,询问
(a, b) 的答案即为树状数组中b 子树的区间和,即sum(dfn_b + siz_b - 1) - sum(dfn_b - 1) 。
最后根据查询的
:::info[代码]
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int c,n,m,q;
vector<int>g[N],revg[N],buk[N];
int tim,ordtim;
int dfn[N],ord[N],dep[N],siz[N],f[N][25],ans[N];
int up[N],mi[N][25];
int bcj[N],tr[N],bsiz[N];
int find(int x){
if(bcj[x]==x)
return x;
return bcj[x]=find(bcj[x]);
}
int lowbit(int x){
return x&-x;
}
void add(int x,int y){
for(int i=x;i<=n;i+=lowbit(i))
tr[i]+=y;
}
int sum(int x){
int res=0;
for(int i=x;i;i-=lowbit(i))
res+=tr[i];
return res;
}
void dfs(int x,int fa){
dfn[x]=++tim;
dep[x]=dep[fa]+1;
f[x][0]=fa;
siz[x]=1;
for(int i=1;i<=19;i++)
f[x][i]=f[f[x][i-1]][i-1];
for(auto y:g[x]){
if(!dfn[y]){
dfs(y,x);
siz[x]+=siz[y];
}
}
ord[++ordtim]=x;
}
int lca(int x,int y){
if(dep[x]<dep[y])
swap(x,y);
int k=dep[x]-dep[y];
for(int i=19;i>=0;i--)
if(k&(1<<i))
x=f[x][i];
if(x==y)
return x;
for(int i=19;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int querymi(int nlca,int y){
int res=up[nlca];
int k=dep[y]-dep[nlca];
for(int i=19;i>=0;i--)
if(k&(1<<i)){
res=min(res,mi[y][i]);
y=f[y][i];
}
return res;
}
struct Que{
int a,b,id;
};
vector<Que>que[N];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
//freopen("planet.in","r",stdin);
//freopen("planet.out","w",stdout);
cin>>n>>m>>q;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
g[x].push_back(y);
revg[y].push_back(x);
}
for(int i=1;i<=n;i++)
sort(g[i].begin(),g[i].end());
dfs(1,0);
for(int i=n;i>=1;i--){
int x=ord[i];
up[x]=dep[x];
for(auto y:revg[x]){
if(y==f[x][0])
continue;
up[x]=min(up[x],querymi(lca(y,x),y));
}
mi[x][0]=up[x];
for(int k=1;k<=19;k++)
mi[x][k]=min(mi[x][k-1],mi[f[x][k-1]][k-1]);
buk[up[x]].push_back(x);
}
for(int i=1;i<=q;i++){
int a,b;
cin>>a>>b;
que[dep[a]].push_back({a,b,i});
}
for(int i=1;i<=n;i++)
bcj[i]=i;
for(int d=n;d>=1;d--){
for(auto x:buk[d+1]){
int s=bsiz[x]+1;
int p=find(f[x][0]);
bsiz[p]+=s;
add(dfn[x],s);
if(p)
add(dfn[p],-s);
bcj[x]=f[x][0];
}
for(auto [a,b,id]:que[d])
ans[id]=sum(dfn[b]+siz[b]-1)-sum(dfn[b]-1);
}
for(int i=1;i<=q;i++)
cout<<ans[i]<<'\n';
return 0;
}
:::