1 条题解
-
0
自动搬运
来自洛谷,原作者为

Aly_
B.Q.A.C.搬运于
2025-08-24 22:30:39,当前版本为作者最后更新于2021-04-17 10:50:13,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
一个究极暴力做法
题意简述
- 给定一张有向图 ,定义一个点 的支配集是所有满足如下性质的点:删除该点后 不再可达 。
- 回答 个询问 ,询问的是加入边 后多少个点的支配集发生变化。
- ,。
解法
一步一步推。
以下是考场上的思考:
- 加入一条边后一个点的支配集要么变小,要么不变。因为这条边使整张图 “ 更加联通 ”。
- 支配的传递关系:若 支配 , 支配 ,则 支配 。因为删除 后 被割开,而 一旦不可达 也就随之不可达了。
- 支配的链式关系:若 支配 , 也支配 ,则 之间也存在支配关系。如不然则必定有一种情况,使得删除其中一个点后, 可从另一个点到达 。
- 支配树:对于一个点 ,设 为它的支配集,**则 中必定有且仅有一个点 ,使得 中除 的点都支配 。**这个性质可由上面的观察得出。我们新建一棵以 为根的树,其中包含所有 无向边,此即为该无向图的支配树。
- 的支配集为支配树上所有 的祖先。
- 的支配集中, 是支配集大小最大的那个点。这点可由前面得出。通过这点可以暴力地构建支配树。
- 加入一条边后, 的支配集发生改变时,要么 的支配集发生改变,要么 不再是 的支配点。这点可由上面支配树的定义看出。
- 加入一条边 后, 不再是 的支配点,当且仅当删除 后 可达 , 可达 。可能有一些诸如 的边角情况,特殊判掉即可。
于是出现了一个很暴力的做法。该做法分为 的预处理和 的询问两部分。
依次遍历所有点,看看把它删掉后哪些点不再可达。这样可以求出每个点的支配集。由前面的第六点思考,我们得以构建支配树。构建完后,对于每个点 ,我们把它的父亲删掉,看看哪些点仍从 可达,哪些点仍可达 。暴力 BFS,复杂度 。
查询时在树上 DFS。运用第七点和第八点综合判定即可。单次复杂度 。
总复杂度 。空间 。可以通过本题。
下面是巨丑考场代码。有微调。
#include<bits/stdc++.h> #define N 3005 using namespace std; int n,m,Q,p,q,fa[N+1],fl[N+1][N+1],t[N+1],tfl[N+1][N+1],gfl[N+1]; vector<int>bi[N+1],fbi[N+1],o[N+1]; pair<int,int>q0[100001]; bool comp(int x,int y){return o[x].size()<o[y].size();} void putin(){ cin>>n>>m>>Q; for(int i=1;i<=m;i++)cin>>p>>q,bi[p].push_back(q),fbi[q].push_back(p); for(int i=1;i<=Q;i++)cin>>q0[i].first>>q0[i].second; } inline void dfs0(int x,int np){ fl[x][np]=1; if(x==np)return; for(int i=0;i<bi[x].size();i++){ int ni=bi[x][i]; if(!fl[ni][np])dfs0(ni,np); } } void ycl(){ dfs0(1,0); for(int i=1;i<=n;i++)t[i]=i; for(int i=1;i<=n;i++){ dfs0(1,i); for(int j=1;j<=n;j++)if(fl[j][0]&&!fl[j][i])o[j].push_back(i); } sort(t+1,t+n+1,comp); for(int i=1;i<=n;i++){ for(int j=0;j<o[i].size();j++){ if(o[o[i][j]].size()==o[i].size()-1){ fa[i]=o[i][j];break; } } } } inline void dfs1(int x,int np,int nr){ if(x==nr)return; tfl[x][np]=1; for(int i=0;i<fbi[x].size();i++){ int ni=fbi[x][i]; if(!tfl[ni][np])dfs1(ni,np,nr); } } void cal0(){ for(int i=2;i<=n;i++){ dfs1(i,i,fa[i]); } for(int i=1;i<=Q;i++){ int nans=0; for(int j=1;j<=n;j++)if(fl[q0[i].first][fa[j]]&&tfl[q0[i].second][j]&&fa[j]!=1&&fa[j]!=q0[i].first)gfl[j]=1; for(int j=1;j<=n;j++)if(gfl[fa[t[j]]])gfl[t[j]]=1; for(int j=1;j<=n;j++)if(gfl[j])nans++,gfl[j]=0; cout<<nans<<'\n'; } } signed main(){ putin(); ycl(); cal0(); return 0; }省选救命题
- 1
信息
- ID
- 6682
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者