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,我们可以用上面的规则产 ...
随机推荐
- Arduino 语法与函数
Arduino programs can be divided in three main parts: structure, values (variables and constants), an ...
- Magicodes.IE 2.4版本发布
今天我们发布了2.4版本,这离不开大家对Magicodes.IE的支持,我们也对大家的意见以及需求不断的进行更新迭代,目前我们的发布频率平均在一周一个beta版本,一个月一个正式版本的更新,我们欢迎更 ...
- PyCharm 上安装 Package(以 pandas 为例)
一.使用 PyCharm 软件安装 pandas 包 1.打开 PyCharm 2.点击右上角 "Files" →"Settings..." 3.弹出" ...
- JS关闭chorme页面
百度到的很多答案都失效了,这是收集一位博主的(https://www.jianshu.com/p/9dc2752194b8),目前可以使用. 代价是打开一个空白页面,能实现无提示关闭当前页面.不需要是 ...
- pytest框架: fixture之conftest.py
原文地址:https://blog.csdn.net/BearStarX/article/details/101000516 一.fixture优势1.fixture相对于setup和teardown ...
- centos8平台使用pstree查看进程树
一,pstree用途 Linux pstree命令将所有行程以树状图显示,树状图将会以 pid (如果有指定) 或是以 systemd 这个基本行程为根 (root) 说明:centos6及更旧版本为 ...
- 3.QOpenGLWidget-通过着色器来渲染渐变三角形
在上章2.通过QOpenGLWidget绘制三角形,我们学习绘制三角形还是单色的,本章将为三角形每个顶点着色. 1.着色器描述 着色器的开头总是要声明版本,接着是输入和输出变量.uniform和m ...
- App在后台运行时如何保存数据到sqlite数据库
iOS程序进入后台后,是不允许读写任何文件和数据库(sqlite),但是允许读写NSUserDefault中的数据. 因此在后台时如果想存储数据,则可使用NSUserDefault(偏好设置)临时保存 ...
- oblivious polynomial evaluation
Oblivious polynomial evaluation is a protocol involving two parties, a sender whose input is a polyn ...
- Hive Sql的日常使用笔记
date: 2019-03-22 17:02:37 updated: 2020-04-08 16:00:00 Hive Sql的日常使用笔记 1. distinct 和 group by distin ...