P10304 题解
DaiRuiChen007 · · 题解
Problem Link
题目大意
给定一张
n 个点m 条边的 DAG,求出以1 为根的 dfs 生成树T ,q 次询问给定a,b ,其中a 在T 中是b 的祖先,查询若删a\to b 在T 上路径的边后,b 在T 上的子树中有多少个点不能从1 出发到达。数据范围:
n,q\le 10^5,m\le 1.5\times 10^5 。
思路分析
先考虑
初始
然后考虑
离线下来维护
时间复杂度
代码呈现
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
int n,m,dep[MAXN],dfn[MAXN],dcnt,st[MAXN][20],deg[MAXN],up[MAXN][20];
vector <int> G[MAXN],E[MAXN],ord,O[MAXN];
void dfs0(int u,int fz) {
dep[u]=dep[fz]+1,dfn[u]=++dcnt,st[dcnt][0]=fz,up[u][0]=fz;
for(int k=1;k<20;++k) up[u][k]=up[up[u][k-1]][k-1];
for(int v:G[u]) {
if(!dfn[v]) E[u].push_back(v),dfs0(v,u);
else O[u].push_back(v);
}
}
int bit(int x) { return 1<<x; }
int cmp(int x,int y) { return dfn[x]<dfn[y]?x:y; }
int LCA(int x,int y) {
if(x==y) return x;
int l=min(dfn[x],dfn[y])+1,r=max(dfn[x],dfn[y]),k=__lg(r-l+1);
return cmp(st[l][k],st[r-bit(k)+1][k]);
}
int f[MAXN],mn[MAXN][20];
int qry(int x,int r) {
int s=f[r];
for(int k=19;~k;--k) if(dep[up[x][k]]>=dep[r]) s=min(s,mn[x][k]),x=up[x][k];
return s;
}
struct SegmentTree {
int tot,tr[MAXN*20],ls[MAXN*20],rs[MAXN*20];
void ins(int u,int x,int l,int r,int &p) {
if(!p) p=++tot;
tr[p]+=x;
if(l==r) return ;
int mid=(l+r)>>1;
u<=mid?ins(u,x,l,mid,ls[p]):ins(u,x,mid+1,r,rs[p]);
}
void merge(int l,int r,int q,int &p) {
if(!q||!p) return p|=q,void();
tr[p]+=tr[q];
if(l==r) return ;
int mid=(l+r)>>1;
merge(l,mid,ls[q],ls[p]),merge(mid+1,r,rs[q],rs[p]);
}
int qry(int ul,int ur,int l,int r,int p) {
if(ul<=l&&r<=ur) return tr[p];
int mid=(l+r)>>1,s=0;
if(ul<=mid) s+=qry(ul,ur,l,mid,ls[p]);
if(mid<ur) s+=qry(ul,ur,mid+1,r,rs[p]);
return s;
}
void del(int ul,int ur,int l,int r,int &p) {
if(ul<=l&&r<=ur) return tr[p]=0,p=0,void();
int mid=(l+r)>>1;
if(ul<=mid) del(ul,ur,l,mid,ls[p]);
if(mid<ur) del(ul,ur,mid+1,r,rs[p]);
tr[p]=tr[ls[p]]+tr[rs[p]];
}
} T;
int rt[MAXN],ans[MAXN];
vector <array<int,2>> qys[MAXN];
void dfs1(int u) {
T.ins(f[u],1,1,n,rt[u]);
for(int v:E[u]) dfs1(v),T.merge(1,n,rt[v],rt[u]);
if(f[u]<n) {
int w=T.qry(f[u]+1,n,1,n,rt[u]);
T.ins(f[u],w,1,n,rt[u]),T.del(f[u]+1,n,1,n,rt[u]);
}
for(auto z:qys[u]) if(z[0]<n) ans[z[1]]=T.qry(z[0]+1,n,1,n,rt[u]);
}
signed main() {
int q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1,u,v;i<=m;++i) scanf("%d%d",&u,&v),G[u].push_back(v),++deg[v];
for(int i=1;i<=n;++i) sort(G[i].begin(),G[i].end());
queue <int> Q;
for(int i=1;i<=n;++i) if(!deg[i]) Q.push(i);
while(Q.size()) {
int u=Q.front(); Q.pop(),ord.push_back(u);
for(int v:G[u]) if(!--deg[v]) Q.push(v);
}
dfs0(1,0);
for(int k=1;k<20;++k) for(int i=1;i+bit(k)-1<=dcnt;++i) {
st[i][k]=cmp(st[i][k-1],st[i+bit(k-1)][k-1]);
}
for(int i=1;i<=n;++i) if(dfn[i]) f[i]=dep[i];
for(int u:ord) if(dfn[u]) {
mn[u][0]=f[u];
for(int k=1;k<20;++k) mn[u][k]=min(mn[u][k-1],mn[up[u][k-1]][k-1]);
for(int v:O[u]) if(dfn[v]) f[v]=min(f[v],qry(u,LCA(u,v)));
}
for(int i=1,a,b;i<=q;++i) scanf("%d%d",&a,&b),qys[b].push_back({dep[a],i});
dfs1(1);
for(int i=1;i<=q;++i) printf("%d\n",ans[i]);
return 0;
}