2020提高组模拟赛7 StormWind
StormWind
时间:4s 空间:512M
题目描述:
风暴城建造的防线错综复杂,可以抽象成一个有$n$个点$m$条边的有向拓扑图,暴风城的最长防线定义为以任意一个点开始能走的最长路径的边数。
由于部落的进攻有所侧重,所以安度因每天会临时下一些命令来调整防线。
第一种 $ty = 1$ $x$点不能被经过。
第二种 $ty = 2$ 必须经过$x$点。
第三种 $ty = 3$ 必须经过输入顺序的第$x$条边。
每一天的调整不会影响到下一天。
求每一天下完命令之后的最长防线。
输入格式:
第一行三个数$n$,$m$,$k$. 分别表示点数、边数、天数。
以后$m$行每行数$x$,表示$x ->y$ 有一条边。以后k行每行两个数$ty,x$;
输出格式:
对于每个询问 输出一行表示其结果
样例输入:
6 5 3
1 2
1 3
1 4
1 5
2 3
1 2
3 1
2 5
样例输出:
1
2
1
数据范围:
对于$20\%$的数据
$n,m,k<=5000$
另有$20\%$的数据
保证 对于 $1<=i<n$, $i$ 与 $i + 1$ 之间有边。
另有$10\%$的数据 没有操作$1$、$2$
对于$100\%$的数据
$n,m,k<=2e5$
拓扑排序
首先先加一个超级源点和超级汇点,可以发现最长路径一定会从超级源点出发,或者结束于超级汇点
首先考虑第二个和第三个操作,要处理出来从源点出发到这个点的最长路$ds[i]$,和从这个点到汇点的最长路$dt[i]$,这个可以通过拓扑序DP更新
对于第二个操作,那么要强制经过这个点,那么答案就是$ds[i]+dt[i]$
对于第三个操作,那么要强制经过边两端的端点,那么答案就是$ds[u]+dt[v]+1$
主要是难以对第一个操作进行处理,考虑钦定某一个点不能经过,最长路径的贡献来自三个部分,这个点“左边”(拓扑序小于这个点的拓扑序)的点,可以贡献从源点到这些点最长的路径;在这个点“右边”(拓扑序大于这个点的拓扑序)的点,可以贡献从这点到汇点最长的路径;还有就是“左边”连到“右边” 的点,贡献就是$ds[i]+dt[j]+1$
考虑如何计算对于每一个点的贡献
从左边推到右边,枚举到第i个点时,要去除$ds[i]$的贡献和连向这个点的边的贡献,就是$ds[j]+1+dt[i]$(存在$j->i$的边),然后加上$dt[i]$的贡献
这个可以用set来维护


#include <bits/stdc++.h>
using namespace std;
const int N=2*1e5+100;
int n,m,k,ds[N],dt[N],s,t,dg[N];
int dout[N],din[N],vi[N],a[N],w;
int ans[N],premax[N],sucmax[N],id[N];
queue <int> q;
multiset <int> S;
multiset <int> :: iterator it;
struct node
{
int u,v;
}sh[N];
vector <int> e[N],E[N],p;
void get()
{
for (int i=1;i<=n;i++)
{
for (int j=0;j<(int)E[i].size();j++)
dg[E[i][j]]++;
}
for (int i=1;i<=n;i++)
{
if (dg[i]==0)
{
q.push(i);
vi[i]=1;
}
}
while (!q.empty())
{
int x=q.front();
q.pop();
a[++w]=x;
for (int i=0;i<(int)E[x].size();i++)
{
int u=E[x][i];
if (vi[u]) continue;
dg[u]--;
if (dg[u]==0) q.push(u),vi[u]=1;
}
}
dt[t]=0;
for (int i=1;i<=n;i++)
{
int x=a[i];
for (int j=0;j<(int)E[x].size();j++)
{
int u=E[x][j];
dt[u]=max(dt[u],dt[x]+1);
}
}
memset(dg,0,sizeof(dg));
memset(vi,0,sizeof(vi));
for (int i=1;i<=n;i++)
{
for (int j=0;j<(int)e[i].size();j++)
dg[e[i][j]]++;
}
for (int i=1;i<=n;i++)
{
if (dg[i]==0)
{
q.push(i);
vi[i]=1;
}
}
w=0;
while (!q.empty())
{
int x=q.front();
q.pop();
a[++w]=x;
for (int i=0;i<(int)e[x].size();i++)
{
int u=e[x][i];
if (vi[u]) continue;
dg[u]--;
if (dg[u]==0) q.push(u),vi[u]=1;
}
}
ds[s]=0;
for (int i=1;i<=n;i++)
{
int x=a[i];
for (int j=0;j<(int)e[x].size();j++)
{
int u=e[x][j];
ds[u]=max(ds[u],ds[x]+1);
}
}
for (int i=1;i<=n;i++) id[a[i]]=i;
for (int i=1;i<=n;i++) premax[i]=max(premax[i],ds[a[i]]);
for (int i=n;i>=1;i--) sucmax[i]=max(sucmax[i+1],dt[a[i]]);
}
inline void del(int x)
{
it=S.lower_bound(x);
S.erase(it);
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&sh[i].u,&sh[i].v);
dout[sh[i].u]++;din[sh[i].v]++;
e[sh[i].u].push_back(sh[i].v);
E[sh[i].v].push_back(sh[i].u);
}
s=n+1;t=n+2;
for (int i=1;i<=n;i++)
{
if (din[i]==0) e[s].push_back(i),E[i].push_back(s);
if (dout[i]==0) e[i].push_back(t),E[t].push_back(i);
}
n+=2;
get();
for (int i=1;i<=n;i++)
{
for (int j=0;j<(int)E[a[i]].size();j++)
{
int u=E[a[i]][j];
del(ds[u]+dt[a[i]]+1);
}
if (!S.empty())it=S.end(),it--,ans[a[i]]=(*it)-2;
ans[a[i]]=max(ans[a[i]],premax[i-1]-1);
ans[a[i]]=max(ans[a[i]],sucmax[i+1]-1);
for (int j=0;j<(int)e[a[i]].size();j++)
{
int u=e[a[i]][j];
S.insert(ds[a[i]]+dt[u]+1);
}
}
while (k--)
{
int ty,x;
scanf("%d%d",&ty,&x);
if (ty==1) printf("%d\n",ans[x]);
if (ty==2) printf("%d\n",ds[x]+dt[x]-2);
if (ty==3) printf("%d\n",ds[sh[x].u]+dt[sh[x].v]-1);
}
}
2020提高组模拟赛7 StormWind的更多相关文章
- ZROI提高组模拟赛05总结
ZROI提高组模拟赛05总结 感觉是目前为止最简单的模拟赛了吧 但是依旧不尽人意... T1 有一半的人在30min前就A掉了 而我花了1h11min 就是一个简单的背包,我硬是转化了模型想了好久,生 ...
- NOIP2017提高组 模拟赛15(总结)
NOIP2017提高组 模拟赛15(总结) 第一题 讨厌整除的小明 [题目描述] 小明作为一个数学迷,总会出于数字的一些性质喜欢上某个数字,然而当他喜欢数字k的时候,却十分讨厌那些能够整除k而比k小的 ...
- NOIP2017提高组 模拟赛13(总结)
NOIP2017提高组 模拟赛13(总结) 第一题 函数 [题目描述] [输入格式] 三个整数. 1≤t<10^9+7,2≤l≤r≤5*10^6 [输出格式] 一个整数. [输出样例] 2 2 ...
- NOIP2017提高组模拟赛 10 (总结)
NOIP2017提高组模拟赛 10 (总结) 第一题 机密信息 FJ有个很奇怪的习惯,他把他所有的机密信息都存放在一个叫机密盘的磁盘分区里,然而这个机密盘中却没有一个文件,那他是怎么存放信息呢?聪明的 ...
- NOIP2017提高组模拟赛 8(总结)
NOIP2017提高组模拟赛 8(总结) 第一题 路径 在二维坐标平面里有N个整数点,Bessie要访问这N个点.刚开始Bessie在点(0,0)处. 每一步,Bessie可以走到上.下.左.右四个点 ...
- NOIP2017提高组模拟赛 9 (总结)
NOIP2017提高组模拟赛 9 (总结) 第一题 星星 天空中有N(1≤N≤400)颗星,每颗星有一个唯一的坐标(x,y),(1≤x,y ≤N).请计算可以覆盖至少K(1≤K≤N)颗星的矩形的最小面 ...
- NOIP2017提高组模拟赛 7(总结)
NOIP2017提高组模拟赛 7(总结) 第一题 斯诺克 考虑这样一个斯诺克球台,它只有四个袋口,分别在四个角上(如下图所示).我们把所有桌子边界上的整数点作为击球点(除了4个袋口),在每个击球点我们 ...
- NOIP2017提高组模拟赛5 (总结)
NOIP2017提高组模拟赛5 (总结) 第一题 最远 奶牛们想建立一个新的城市.它们想建立一条长度为N (1 <= N <= 1,000,000)的 主线大街,然后建立K条 (2 < ...
- NOIP2017提高组模拟赛4 (总结)
NOIP2017提高组模拟赛4 (总结) 第一题 约数 设K是一个正整数,设X是K的约数,且X不等于1也不等于K. 加了X后,K的值就变大了,你可以重复上面的步骤.例如K= 4,我们可以用上面的规则产 ...
随机推荐
- 联赛模拟测试10 C. 射手座之日
题目描述 分析 方法一(线段树) 线段树维护的是以当前节点为左端点的区间的贡献 而区间的右端点则会从 \(1\) 到 \(n\) 逐渐右移 当我们把右端点从 \(i-1\) 的位置扩展到 \(i\) ...
- 【Flutter Widgets大全】电子书开源
[Flutter Widgets大全]是老孟耗费大量精力整理的,总共有330多个组件的详细用法,开源到Github上,希望可以帮助到大家,开源不易,点个赞可不可以. [Flutter Widgets ...
- 用C写一个简单的推箱子游戏(一)
我现在在读大二,我们有一门课程叫<操作系统>,课程考查要求我们可以写一段程序或者写Windows.iOS.Mac的发展历程.后面我结合网上的资料参考,就想用自己之前简单学过的C写一关的推箱 ...
- 《流畅的Python》第二部分 数据结构 【序列构成的数组】【字典和集合】【文本和字节序列】
第二部分 数据结构 第2章 序列构成的数组 内置序列类型 序列类型 序列 特点 容器序列 list.tuple.collections.deque - 能存放不同类型的数据:- 存放的是任意类型的对象 ...
- GIT 保存日志并建立自己的分支
以下是我个人在工作中对git的愚见全是大白话说明.也是我踩坑记录吧,防止下次再次踩坑. 再已有的dev(开发分支)新建自己的分支 (featuer)在更新到gitlab 仓库中的过程. 首先要有大致的 ...
- 多测师讲解接口测试 _postman(下)_高级讲师肖sir
关联接口 定义:上个接口返回的参数作为下一个接口的入参 1)接口1:查询出所有的州,自治区,直辖市,省(且发送请求不需要入参) 接口url地址: http://www.webxml.com.cn/We ...
- 营口6378.7939(薇)xiaojie:营口哪里有xiaomei
营口哪里有小姐服务大保健[微信:6378.7939倩儿小妹[营口叫小姐服务√o服务微信:6378.7939倩儿小妹[营口叫小姐服务][十微信:6378.7939倩儿小妹][营口叫小姐包夜服务][十微信 ...
- MeteoInfoLab脚本示例:添加南海脚图
添加南海脚图实际上就是增加一个地图坐标系(Axesm),在用axesm函数创建地图坐标系的时候可以指定position参数(即位置和大小),第1和第2个参数是坐标系的左下角x, y位置,后两个参数是坐 ...
- 【Linux教程】Linux系统零基础编程入门,想当大神?这些你都要学
✍ 文件和文件系统 文件是Linux系统中最重要的抽象,大多数情况下你可以把linux系统中的任何东西都理解为文件,很多的交互操作其实都是通过文件的读写来实现的. 文件描述符 在Linux内核中,文件 ...
- matplotlib 饼状图
import matplotlib.pyplot as plt import matplotlib as mpl # 支持中文 plt.rcParams['font.sans-serif'] = [' ...