[关闭]
@xiaoziyao 2021-04-20T03:37:16.000000Z 字数 2402 阅读 937

P7520 [省选联考 2021 A 卷] 支配解题报告

解题报告


P7520 [省选联考 2021 A 卷] 支配

更好的阅读体验

题意

定义一个点支配另一个点当且仅当结点到达结点的每一条路径都要经过,且点的受支配集为所有支配形成的集合。

给定一个个点条边的图,进行次相互独立的询问,每次询问加入边后有多少个点的受支配集有变化。

分析

似乎是支配树裸题,但我不会支配树/kk。

当我们不知道支配树时,应该怎么想到支配树呢?

考虑到结点的所有路径一定是不断“扩张”然后不断“收束”到一个点上,然后继续“扩张”与“收束”的一个过程,而每次“收束”到的点都是的支配点。

不难发现除了结点外任意结点都有且仅有一个极大支配点,也就是说,那么如果我们将连一条边的话,根据支配的定义一定不会形成环,那么就会形成一个个结点,条边的无向无环联通图——支配树。

如何建出支配树呢?这里介绍一种的简单做法。

考虑设表示删除结点后,结点是否能到达结点,那么我们只需要枚举,然后每次就可以的求出这个数组了。

又由于支配等价,因此我们可以求出所有结点的受支配集。

那么我们对于每个点枚举它受支配集中每一个点,按照极大支配点的定义进行判断就好了。

建出支配树,又怎么求解呢?(设加入的边为

对于每一个点,不难发现它的受支配集会改变当且仅当的受支配集改变或者不再支配。(由极大支配点的定义可得)

那么我们从上到下遍历支配树(不要直接遍历,最好用序或者序,本文使用序,也就是所有点按照支配集大小进行排序的结果),问题转化为判断一个点的极大支配点是否还支配

很容易发现支配树的支配关系是等价于原图的(这也是CCF设置图是一个树这个部分分的原因),那么我们只需要判断删除的父亲从是否能到达,而是否能到达就好了。

那么我们再预处理一个表示删除的父亲后是否能到达就做完这道题了。

时间复杂度:

代码

被卡常了,交换了定义中的才能过。

  1. #include<stdio.h>
  2. #include<vector>
  3. #include<algorithm>
  4. using namespace std;
  5. const int maxn=3005;
  6. int n,m,q,e;
  7. int bfn[maxn],fa[maxn],t[maxn],ok[maxn];
  8. int delp[maxn][maxn],delf[maxn][maxn];//delp[y][x]: del x 1 to y ; delf[y][x]: del fa[x] 1 to y
  9. vector<int>g[maxn],rg[maxn],d[maxn];
  10. inline int cmp(int x,int y){
  11. return d[x].size()<d[y].size();
  12. }
  13. void getdelp(int x,int p){
  14. if(x==p)
  15. return ;
  16. delp[x][p]=1;
  17. for(int i=0;i<g[x].size();i++){
  18. int y=g[x][i];
  19. if(delp[y][p]==0)
  20. getdelp(y,p);
  21. }
  22. }
  23. void getdelf(int x,int p){
  24. if(x==fa[p])
  25. return ;
  26. delf[x][p]=1;
  27. for(int i=0;i<rg[x].size();i++){
  28. int y=rg[x][i];
  29. if(delf[y][p]==0)
  30. getdelf(y,p);
  31. }
  32. }
  33. void read(int &x){
  34. x=0;
  35. char c=getchar();
  36. for(;c<'0'||c>'9';c=getchar());
  37. for(;c>='0'&&c<='9';c=getchar())
  38. x=x*10+c-48;
  39. }
  40. int main(){
  41. scanf("%d%d%d",&n,&m,&q);
  42. for(int i=1;i<=m;i++){
  43. int x,y;
  44. read(x),read(y);
  45. g[x].push_back(y),rg[y].push_back(x);
  46. }
  47. for(int i=1;i<=n;i++){
  48. getdelp(1,i);
  49. for(int j=1;j<=n;j++)
  50. if(delp[j][i]==0)
  51. d[j].push_back(i);
  52. }
  53. for(int i=2;i<=n;i++)
  54. for(int j=0;j<d[i].size();j++)
  55. if(d[d[i][j]].size()==d[i].size()-1){
  56. fa[i]=d[i][j];
  57. break;
  58. }
  59. for(int i=1;i<=n;i++)
  60. bfn[i]=i;
  61. sort(bfn+1,bfn+1+n,cmp);
  62. for(int i=2;i<=n;i++)
  63. getdelf(i,i);
  64. for(int i=1;i<=q;i++){
  65. int x,y,res=0;
  66. read(x),read(y);
  67. for(int j=1;j<=n;j++)
  68. if(fa[j]!=1&&fa[j]!=x&&delp[x][fa[j]]&&delf[y][j])
  69. ok[j]=1;
  70. for(int j=2;j<=n;j++){
  71. ok[bfn[j]]|=ok[fa[bfn[j]]];
  72. res+=ok[bfn[j]];
  73. }
  74. for(int j=1;j<=n;j++)
  75. ok[j]=0;
  76. printf("%d\n",res);
  77. }
  78. return 0;
  79. }

省选联考A卷全部题解可见:2021省选联考A卷解题报告

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注