题目传送门(内部题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. CodeIgniter 技巧 - 通过 Composer 安装 CodeIgniter 框架并安装依赖包

    PHP 项目中,通过 Composer 来管理各种依赖包,类似 Java 中的 Maven,或 Node 中的 npm.CodeIgniter 框架要想通过 Composer 自动加载包也很简单,步骤 ...

  2. vue-安装及新建一个项目

    1.首先我们需要安装node.js,下载地址是:https://nodejs.org/en/ 之后是node.js的正常安装步骤: 接着打开window+R输入cmd回车进入命令行模块 2.确认nod ...

  3. 网络设备MIB浏览器ifType、ifDescr、ifMtu、ifInOctets等的含义(Zabbix SNMP)

    1.ifType 接口的类型 取值117表示接口为GigabitEthernet (取值62表示接口为 FastEnthernet) 2.ifDescr 接口类型的描述 有GigabitEtherne ...

  4. 【OpenGL】---认识CubeTexture

    一.OpenGL Cube Texture 立方体纹理 立方体纹理是一种特殊的纹理技术,他用6幅二维贴图构成一个以原点为中心的纹理立方体.对于每个片段,纹理坐标(s,t,r)被当做三维向量看待,每个纹 ...

  5. 为什么 Kafka 速度那么快?

    来源:cnblogs.com/binyue/p/10308754.html Kafka的消息是保存或缓存在磁盘上的,一般认为在磁盘上读写数据是会降低性能的,因为寻址会比较消耗时间,但是实际上,Kafk ...

  6. [Bzoj2243][SDOI2011]染色(线段树&&树剖||LCT)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2243 线段树+树链剖分,在线段树需要每次用lt和rt两个数组记录当前区间的左右边界的颜色 ...

  7. Using Keyboard Navigation

    http://technet.microsoft.com/en-us/library/cc939835.aspx

  8. Codeforces - 1191F - Tokitsukaze and Strange Rectangle - 组合数学 - 扫描线

    https://codeforces.com/contest/1191/problem/F 看了一下题解的思路,感觉除了最后一段以外没什么启发. 首先离散化x加快速度,免得搞多一个log.其实y不需要 ...

  9. cdn.bootcss.com无法访问 解决方法

    今天angularjs的网站突然加载报错,提示Refused to execute script from 'https://cdnjs.com/' because its MIME type ('t ...

  10. elasticsearch 基础 —— Inner hits

    Inner hits The parent-join and nested 功能允许返回具有不同范围匹配的文档.在父/子案例中,基于子文档中的匹配返回父文档,或者基于父文档中的匹配返回子文档.在嵌套的 ...