题目传送门(内部题55)


输入格式

第一行,包含两个整数:$n,m,q$,表示敌军城市数、路数和情报数。
接下来$m$行,每行包含两个整数:$u,v$,表示从$u$到$v$包含一条单向道路。
接下来$q$行,每行包含一些整数:$k\ u_1\ u_2...u_k$,表示敌军会向$u_1...u_k$这$k$个城市派遣大军。


输出格式

对于每个询问,输出一行包含一个整数表示必经的城市数。


样例

样例输入1:

4 3 2
1 2
2 3
2 4
2 3 4
2 2 4

样例输出1:

2
2

样例输入2:

4 4 1
1 2
1 3
2 4
3 4
1 4

样例输出2:


数据范围与提示

样例$1$解释:

两个询问的必经点为:$1,2$

样例$2$解释:

询问的必经点为:$1,4$

数据范围:

对于$10\%$的数据,$1\leqslant n\leqslant 7,1\leqslant m\leqslant 10,1\leqslant q\leqslant 100$;
对于$40\%$的数据,$1\leqslant n\leqslant 50,000,m=n-1,1\leqslant q\leqslant 100,000$;
对于$100\%$的数据,$1\leqslant n\leqslant 50,000,1\leqslant m\leqslant 100,000,1\leqslant q\leqslant 100,000,\sum k\leqslant 100,000$。


题解

首先,想吐槽一下出题人,下面是官方题解中的第一句话:

可能是因为我的语文真的不好,反正我是没看出来是$DAG$,然而就因为这个打乱了我整场考试的节奏。

两种解法,我们一一道来:

$1.$支配树:

支配树板子题,简单讲一下

对于$40\%$的数据,是一棵树,我们无非就是求出$k$个数的$lca$,然后$depth[lca]$就是答案。

那么我们现在考虑不是一棵树的情况,就像样例$2$,会是类似下面的一张图:

对于点$6$,从$1$到它的必经点就是$1,2,5,6$,那么我们考虑如何求出这个答案。

对于$DAG$,我们就考虑$topsort$。

还是考虑利用树的情况的$depth[lca]$,那么我们就是想办法将$5$的直接父亲设为$2$即可。

思考一下下面的操作:

  $\alpha.$如果一个点第一次被访问,那么就现将它的父亲设为指向它的点;如上图中,相当于$3\sim 5$和$4\sim 5$都没有被经过过,现在我们走了$3\sim 5$这条边,然后我们先将$5$的直接父亲设为$3$。

  $\beta.$如果这个点已经被访问过了,那么我们将它的直接父亲设为现在指向它的这个点和现在所记录的这个点的直接父亲的$lca$;如上图中,相当于我们已经经过了$3\sim 5$这条边,然而还没有经过过$4\sim 5$这条边,现在我们走了$4\sim 5$这条边,然后我们要将$5$这个点的直接父亲设置为$3$和$4$的$lca$,即为$2$号点。

而对于上面这张图,你可以将其理解为我们将其变为了下图:

重复上面的操作,直到完成整个$topsort$,我们也就相当于将其变成了一棵树,也就转化成了$40\$数据的解法。

时间复杂度:$\Theta(k\log n)$。

期望得分:$100$分。

实际得分:$100$分。

$2.bitset$:

这个就很简单了,无非就是利用$bitset$记录一下必须经过的点,还是分为两种情况:

  $\alpha.$还没有被访问过,直接将指向它的点的$bitset$传给它,不要忘了它自己。

  $\beta.$被访问过,那么将它的$bitset$与指向它的$bitset$取$\&$即可。

注意空间问题,需要将$bitset$开一半,然后先处理编号前$25000$的点,然后再处理编号后$25000$号点,否则空间会超;答案就是两次处理出来的$.count()$的和。

时间复杂度:$\Theta(\frac{k\times n}{32})$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

支配树:

#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to;}e[100001];
int head[50001],cnt;
int n,m,q,k;
int du[50001];
int depth[50001],fa[50001][21];
int que[50001];
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
int LCA(int x,int y)
{
if(depth[x]<depth[y])swap(x,y);
for(int i=20;i>=0;i--)
if(depth[fa[x][i]]>=depth[y])x=fa[x][i];
if(x==y)return x;
for(int i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
void topsort()
{
que[1]=depth[1]=1;
int h=0,t=1;
while(h<=t)
{
h++;
depth[que[h]]=depth[fa[que[h]][0]]+1;
for(int i=1;i<=20;i++)
fa[que[h]][i]=fa[fa[que[h]][i-1]][i-1];
for(int i=head[que[h]];i;i=e[i].nxt)
{
if(!fa[e[i].to][0])fa[e[i].to][0]=que[h];
else fa[e[i].to][0]=LCA(fa[e[i].to][0],que[h]);
du[e[i].to]--;
if(!du[e[i].to])que[++t]=e[i].to;
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);du[y]++;
}
topsort();
while(q--)
{
int lca;
scanf("%d%d",&k,&lca);
k--;while(k--)
{
int x;
scanf("%d",&x);
lca=LCA(lca,x);
}
printf("%d\n",depth[lca]);
}
return 0;
}

$bitset$:

#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to;}e[100001];
int head[50001],cnt;
int n,m,q;
int du[2][50001];
int que[50001];
int k[100001];
int ans[100001];
bool vis[50001];
vector<int> question[100001];
bitset<25000> bit[50001],flag;
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void topsort1()
{
que[1]=1;
int h=0,t=1;
while(h<=t)
{
h++;
if(que[h]<=25000)bit[que[h]][que[h]]=1;
for(int i=head[que[h]];i;i=e[i].nxt)
{
if(vis[e[i].to])bit[e[i].to]&=bit[que[h]];
else
{
bit[e[i].to]=bit[que[h]];
vis[e[i].to]=1;
}
du[0][e[i].to]--;
if(!du[0][e[i].to])
que[++t]=e[i].to;
}
}
}
void topsort2()
{
que[1]=1;
int h=0,t=1;
while(h<=t)
{
h++;
if(que[h]>25000)bit[que[h]][que[h]-25000]=1;
for(int i=head[que[h]];i;i=e[i].nxt)
{
if(vis[e[i].to])bit[e[i].to]&=bit[que[h]];
else
{
bit[e[i].to]=bit[que[h]];
vis[e[i].to]=1;
}
du[1][e[i].to]--;
if(!du[1][e[i].to])
que[++t]=e[i].to;
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
du[0][y]++;
du[1][y]++;
}
topsort1();
for(int i=1;i<=q;i++)
{
int x;scanf("%d%d",&k[i],&x);
question[i].push_back(x);
flag=bit[x];
for(int j=2;j<=k[i];j++)
{
scanf("%d",&x);
flag&=bit[x];
question[i].push_back(x);
}
ans[i]=flag.count();
}
for(int i=1;i<=50000;i++)bit[i]&=0;
memset(vis,0,sizeof(vis));
topsort2();
for(int i=1;i<=q;i++)
{
flag=bit[question[i][0]];
for(int j=1;j<k[i];j++)
flag&=bit[question[i][j]];
printf("%d\n",ans[i]+flag.count());
}
return 0;
}

rp++

[CSP-S模拟测试]:attack(支配树+LCA+bitset)的更多相关文章

  1. 2018.06.27 NOIP模拟 节目(支配树+可持久化线段树)

    题目背景 SOURCE:NOIP2015-GDZSJNZX(难) 题目描述 学校一年一度的学生艺术节开始啦!在这次的艺术节上总共有 N 个节目,并且总共也有 N 个舞台供大家表演.其中第 i 个节目的 ...

  2. [07/18NOIP模拟测试5]超级树

    鬼能想到的dp定义:dp[i][j]表示在一棵i级超级树中,有j条路径同时存在且这j条路径没有公共点时,可能的情况数 刚开始我也没看懂,所以举个例子 如一个2级的超级树,父节点为1,左右儿子为2,3 ...

  3. [CSP-S模拟测试]:Walk(树的直径+数学)

    题目描述 给定一棵$n$个节点的树,每条边的长度为$1$,同时有一个权值$w$.定义一条路径的权值为路径上所有边的权值的最大公约数.现在对于任意$i\in [1,n]$,求树上所有长度为$i$的简单路 ...

  4. [CSP-S模拟测试]:柱状图(树状数组+二分+三分)

    题目描述 $WTH$获得了一个柱状图,这个柱状图一共有$N$个柱子,最开始第$i$根柱子的高度为$x_i$,他现在要将这个柱状图排成一个屋顶的形状,屋顶的定义如下:$1.$屋顶存在一个最高的柱子,假设 ...

  5. [CSP-S模拟测试]:count(树分块)

    题目描述 李华终于逃离了无尽的英语作文,重获自由的他对一棵树产生了兴趣.首先,他想知道一棵树是否能分成大小相同的几块(即切掉一些边,使得每个连通块的点数相同).然后,他觉得这个问题过于简单,于是他想知 ...

  6. [CSP-S模拟测试]:影魔(树状数组+线段树合并)

    题目背景 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己 ...

  7. [7.18NOIP模拟测试5]砍树 题解(数论分块)

    题面(加密) 又考没学的姿势……不带这么玩的…… 考场上打了个模拟 骗到30分滚粗了 稍加思考(滑稽)可将题面转化为: 求一个最大的$d$,使得 $\sum \limits _{i=1}^n {(\l ...

  8. [CSP-S模拟测试]:统计(树状数组+乱搞)

    题目传送门(内部题120) 输入格式 第一行,两个正整数$n,m$. 第二行,$n$个正整数$a_1,a_2,...,a_n$,保证$1\leqslant a_i\leqslant n$,可能存在相同 ...

  9. [CSP-S模拟测试51]题解

    错失人生中第一次AK的机会…… A.attack 支配树板子题.考场上发明成功√ 首先支配树上两点路径之间的点都是必经之点,根据这个性质我们就可以yy出建树的方法.跑拓扑,在每个点(设为$x$)即将入 ...

随机推荐

  1. 第 12 章 python并发编程之协程

    一.引子 主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只用一个)情况下实现并发,并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作 ...

  2. Oracle11g安装步骤

    plsql安装等:https://blog.csdn.net/li66934791/article/details/83856225      https://www.cnblogs.com/gaoz ...

  3. 学习:多项式算法----FFT

    FFT,即快速傅里叶变换,是离散傅里叶变换的快速方法,可以在很低复杂度内解决多项式乘积的问题(两个序列的卷积) 卷积 卷积通俗来说就一个公式(本人觉得卷积不重要) $$C_k=\sum_{i+j=k} ...

  4. get_date.sh

    #!/usr/bin#####################################################################日期函数处理#获取某个月份的天数 getM ...

  5. Web Service-第一篇什么是Web Service

    1.什么是WebService? WebService是一种跨编程语言和跨操作系统平台的远程调用技术.WebService就是一个应用程序向外界暴露出一个能通过Web进行调用的API,也就是说能用编程 ...

  6. mysql双主+keepalived架构

    架构展示 操作系统 centos6.5 数据库 mysql5.7 master1 10.0.254.148 master2 10.0.254.147 VIP 10.0.254.88 (keepaliv ...

  7. grep命令用关系或查询多个字符串

    bcmsh ps | grep -E 'port|ge2 ' bcmsh ps | grep 'port\|ge2 ' 我的目的是筛选出含有 ‘port’ 或者含有 ‘ge2 ’ 的行,上面的第一行参 ...

  8. Python之获取文件夹中文件列表以及glob与fnmatch模块的使用

    获取文件夹中的文件列表 print(os.listdir("../secondPackage")) # ['__init__.py', 'secondCookBook.py', ' ...

  9. Python之文件路径名的操作

    使用 os.path 模块中的函数来操作路径名 import os # 获取当前文件路径 path=os.path.abspath(__file__) # 获取绝对路径 /home/zzy/Pycha ...

  10. 【记录】ajax 设置请求header的Content-Type 为 application/json;charset=utf8

    具体案例如下 $.ajax({ url: context.state.IpccSendIm, method: 'POST', data: JSON.stringify(val), headers:{' ...