洛谷题面传送门

真·支配树不 sb 的题。

首先题面已经疯狂暗示咱们建出支配树对吧,那咱就老老实实建呗。由于这题数据范围允许 \(n^2\)​ 算法通过,因此可以考虑 \(\mathcal O(n^2)\)​ 地建立支配树,具体来说我们枚举每个点 \(x\)​,将这个点暂时地从图中删除,如果对于图中另一个点 \(y\)​ 满足删除 \(x\) 后 \(1\) 不能到达 \(y\),那么 \(x\) 就在 \(y\) 的支配集中,这样我们再对整个 DAG DFS 一遍求出每个点的 DFS 序,然后取 DFS 序最大的点作为每个点在支配树上的父亲即可。

接下来考虑怎样计算答案。首先显然的一件事情是,我们加入一条边后最多只会让某些点的支配集大小变小,而不会使支配集大小变大,因此我们只需考虑有哪些点在加入这条边后,存在某个点原来能支配它而现在不能即可。注意到一个性质,就是对于一个点 \(x\)​,如果 \(fa_x\)​(当然有些人喜欢称这个东西为 \(idom_x\)​,反正能看懂就行了吧)的支配集改变,那么 \(x\)​ 的支配集也会改变。因为根据支配树的性质,每个点的支配集一定是该点到 \(1\)​ 路径上所有点组成的集合,因此如果 \(fa_x\)​ 的支配集改变,就必然存在某个 \(fa_x\)​ 的祖先 \(y\)​,满足存在路径 \(1\to fa_x\)​ 且不经过 \(y\)​,这样就存在路径 \(1\to fa_x\to x\)​ 不经过 \(x\)​,\(y\)​ 就从 \(x\)​ 的支配集中消失了。同理,如果 \(fa_x\)​ 的支配集没变,但 \(x\)​ 的支配集改变,必然是因为 \(fa_x\)​ 无法支配 \(x\)​,因为如果存在某个 \(x\)​ 的祖先 \(y\ne fa_x\)​,满足 \(y\) 不再支配 \(x\) 且 \(y\) 能支配 \(fa_x\),那就能推出这个 \(1\to x\) 且不经过 \(y\) 的路径肯定不经过 \(fa_x\),从而 \(fa_x\) 不支配 \(x\)。

因此我们考虑每次询问对整棵树进行 DFS,如果走到一个点发现 \(fa_x\) 不支配 \(x\),答案就加上 \(x\) 子树的大小并 return,那么怎么判断 \(fa_x\) 是否支配 \(x\) 呢?显然如果 \(fa_x\) 不支配 \(x\) 那么必然存在路径 \(1\to u\to v\to x\) 满足这条路径不经过 \(fa_x\),而这又 obviously 等价于 \(1\to u,v\to x\) 均不经过 \(fa_x\),前者可以通过建支配树时预处理出的“删掉点 \(x\) 后是否存在 \(1\to y\) 的路径的数组 \(ban_{x,y}\)”求出,而关于后者我们发现都是形如”删掉 \(fa_x\) 后 \(x\) 能否在反图上到达 \(y\)“,因此我们再建一个 \(ban\_fa_{x,y}\) 维护这个东西即可。时间复杂度 \(\mathcal O(n^2+nq)\)

卡常技巧:交换 \(ban\) 和 \(ban\_fa\) 的两维后,效率大约能快 25%,具体原理见这儿

  1. const int MAXN=3e3;
  2. const int MAXM=MAXN<<1;
  3. int n,m,qu;
  4. struct graph{
  5. int hd[MAXN+5],nxt[MAXM+5],to[MAXM+5],ec=0;
  6. void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
  7. } g,rv_g,dt;
  8. int dfn[MAXN+5],rid[MAXN+5],tim=0,fa[MAXN+5];
  9. bool ban[MAXN+5][MAXN+5],ban_fa[MAXN+5][MAXN+5];
  10. void dfs(int x){
  11. rid[dfn[x]=++tim]=x;
  12. for(int e=g.hd[x];e;e=g.nxt[e]){
  13. int y=g.to[e];if(!dfn[y]) dfs(y);
  14. }
  15. }
  16. void dfs_ban(int x,int ban_id){
  17. if(x==ban_id) return;ban[x][ban_id]=1;
  18. // printf("{%d,%d}\n",ban_id,x);
  19. for(int e=g.hd[x];e;e=g.nxt[e]){
  20. int y=g.to[e];
  21. if(!ban[y][ban_id]) dfs_ban(y,ban_id);
  22. }
  23. }
  24. void dfs_ban_fa(int x,int ban_id){
  25. if(x==fa[ban_id]) return;ban_fa[x][ban_id]=1;
  26. for(int e=rv_g.hd[x];e;e=rv_g.nxt[e]){
  27. int y=rv_g.to[e];
  28. if(!ban_fa[y][ban_id]) dfs_ban_fa(y,ban_id);
  29. }
  30. }
  31. int siz[MAXN+5];
  32. void dfssiz(int x){
  33. siz[x]=1;
  34. for(int e=dt.hd[x];e;e=dt.nxt[e]){
  35. int y=dt.to[e];dfssiz(y);
  36. siz[x]+=siz[y];
  37. }
  38. }
  39. int X,Y,res=0;
  40. void dfscalc(int x){
  41. if(x^1){
  42. if(ban[X][fa[x]]&&ban_fa[Y][x]){
  43. res+=siz[x];return;
  44. }
  45. } for(int e=dt.hd[x];e;e=dt.nxt[e]){
  46. int y=dt.to[e];dfscalc(y);
  47. }
  48. }
  49. int main(){
  50. scanf("%d%d%d",&n,&m,&qu);
  51. for(int i=1,u,v;i<=m;i++){
  52. scanf("%d%d",&u,&v);
  53. g.adde(u,v);rv_g.adde(v,u);
  54. } dfs(1);for(int i=1;i<=n;i++) dfs_ban(1,i);
  55. // for(int i=1;i<=n;i++) printf("%d %d\n",dfn[i],rid[i]);
  56. for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
  57. if(!ban[j][i]&&(i^j)) chkmax(fa[j],dfn[i]);
  58. for(int i=2;i<=n;i++) fa[i]=rid[fa[i]];fa[1]=0;
  59. for(int i=2;i<=n;i++) dt.adde(fa[i],i),dfs_ban_fa(i,i);
  60. // for(int i=2;i<=n;i++) printf("%d\n",fa[i]);
  61. dfssiz(1);
  62. while(qu--){scanf("%d%d",&X,&Y);res=0;dfscalc(1);printf("%d\n",res);}
  63. return 0;
  64. }

洛谷 P7520 - [省选联考 2021 A 卷] 支配(支配树)的更多相关文章

  1. 洛谷 P7515 - [省选联考 2021 A 卷] 矩阵游戏(差分约束)

    题面传送门 emmm--怎么评价这个题呢,赛后学完差分约束之后看题解感觉没那么 dl,可是现场为啥就因为种种原因想不到呢?显然是 wtcl( 先不考虑"非负"及" \(\ ...

  2. 洛谷 P7516 - [省选联考 2021 A/B 卷] 图函数(Floyd)

    洛谷题面传送门 一道需要发现一些简单的性质的中档题(不过可能这道题放在省选 D1T3 中偏简单了?) u1s1 现在已经是 \(1\text{s}\)​ \(10^9\)​ 的时代了吗?落伍了落伍了/ ...

  3. 洛谷P6623——[省选联考 2020 A 卷] 树

    传送门:QAQQAQ 题意:自己看 思路:正解应该是线段树/trie树合并? 但是本蒟蒻啥也不会,就用了树上二次差分 (思路来源于https://www.luogu.com.cn/blog/dengy ...

  4. 洛谷 P6624 - [省选联考 2020 A 卷] 作业题(矩阵树定理+简单数论)

    题面传送门 u1s1 这种题目还是相当套路的罢 首先看到 \(\gcd\) 可以套路地往数论方向想,我们记 \(f_i\) 为满足边权的 \(\gcd\) 为 \(i\) 的倍数的所有生成树的权值之和 ...

  5. [题解] LOJ 3300 洛谷 P6620 [省选联考 2020 A 卷] 组合数问题 数学,第二类斯特林数,下降幂

    题目 题目里要求的是: \[\sum_{k=0}^n f(k) \times X^k \times \binom nk \] 这里面出现了给定的多项式,还有组合数,这种题目的套路就是先把给定的普通多项 ...

  6. [省选联考 2021 A 卷] 矩阵游戏

    很巧妙的一个构造. 我是没有想到的. 自己的思维能力可能还是不足. 考虑先满足\(b\)对\(a\)的限制,把\(a\)的第一行和第一列设\(0\),推出这个\(a\). 接下来考虑对这个\(a\), ...

  7. [省选联考 2021 A/B 卷] 卡牌游戏

    垃圾福建垫底选手来看看这题. 大家怎么都写带 \(log\) 的. 我来说一个线性做法好了. 那么我们考虑枚举 \(k\) 作为翻转完的最小值. 那么构造出一个满足条件的操作,我们在 \(a_i\) ...

  8. [省选联考 2020 A 卷] 组合数问题

    题意 [省选联考 2020 A 卷] 组合数问题 想法 自己在多项式和数论方面还是太差了,最近写这些题都没多少思路,看完题解才会 首先有这两个柿子 \(k*\dbinom{n}{k} = n*\dbi ...

  9. luoguP6623 [省选联考 2020 A 卷] 树(trie树)

    luoguP6623 [省选联考 2020 A 卷] 树(trie树) Luogu 题外话: ...想不出来啥好说的了. 我认识的人基本都切这道题了. 就我只会10分暴力. 我是傻逼. 题解时间 先不 ...

随机推荐

  1. 从零到熟悉,带你掌握Python len() 函数的使用

    摘要:本文为你带来如何找到长度内置数据类型的使用len() 使用len()与第三方数据类型 提供用于支持len()与用户定义的类. 本文分享自华为云社区<在 Python 中使用 len() 函 ...

  2. 【c++ Prime 学习笔记】第12章 动态内存

    对象的生存期: 全局对象:程序启动时创建,程序结束时销毁 局部static对象:第一次使用前创建,程序结束时销毁 局部自动对象:定义时创建,离开定义所在程序块时销毁 动态对象:生存期由程序控制,在显式 ...

  3. LeetCode:回溯算法

    回溯算法 这部分主要是学习了 labuladong 公众号中对于回溯算法的讲解 刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 总结 概述 回溯是 DFS 中的一种技巧.回溯法采用 ...

  4. Python使用阿里云OSS服务

    Python使用阿里云OSS服务 前言: 在远程搭建了一个平台,通过改远程平台进行数据的采集,需要将数据内容传送至本地进行处理:为了实现该功能,考虑了阿里云的OSS对象储存的服务. 40G包月只需1元 ...

  5. 需求存在,功能存在——Alpha阶段性总结

    0.Alpha开发成果 题士Alpha发布报告 题士开发记录 1.任务划分 Alpha阶段大致将任务划分为Design,Develop和Test三类 Design型任务包含页面UI设计和接口API设计 ...

  6. [对对子队]会议记录5.27(Scrum Meeting12)

    今天已完成的工作 朱俊豪 ​ 工作内容:寻找电池模型和BGM,修改关卡选择场景 ​ 相关issue:优化初步导出版本 ​ 相关签入:perf:地图界面优化 feat:更新系列资源(星星,大电池) 何瑞 ...

  7. UltraSoft - Alpha - Scrum Meeting 4

    Date: Apr 18th, 2020. 会议内容为 例行汇报. Scrum 情况汇报 进度情况 组员 负责 前两日进度 后两日任务 CookieLau PM 完成前后端交互规格的约定,了解前后端进 ...

  8. 百度OCR技术博客

    百度OCR工具链使用 百度OCR的API使用总体来说比较容易,主要步骤为:注册云平台并登录,选择服务并创建应用,保存API Key以及Secret Key,选择调用API. 注册登录百度云平台 首先需 ...

  9. Noip模拟59 2021.9.22

    新机房首模拟变倒数 T1 柱状图 关于每一个点可以做出两条斜率分别为$1,-1$的直线, 然后题意转化为移动最少的步数使得所有点都在某一个点的两条直线上 二分出直线的高度,判断条件是尽量让这条直线上部 ...

  10. vue混入mixin的使用,保证你看的明明白白!

    场景描述 有些时候,我们发现有些组件部分功能代码是几乎是一样的. 这个时候,我们就可以将相同的逻辑代码抽离出来 此时我们的主角混入mixin就登场了 下面我们有a-test和b-test两个组件,点击 ...