StormWind

中文 切换语言(Change Language)

时间: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的更多相关文章

  1. ZROI提高组模拟赛05总结

    ZROI提高组模拟赛05总结 感觉是目前为止最简单的模拟赛了吧 但是依旧不尽人意... T1 有一半的人在30min前就A掉了 而我花了1h11min 就是一个简单的背包,我硬是转化了模型想了好久,生 ...

  2. NOIP2017提高组 模拟赛15(总结)

    NOIP2017提高组 模拟赛15(总结) 第一题 讨厌整除的小明 [题目描述] 小明作为一个数学迷,总会出于数字的一些性质喜欢上某个数字,然而当他喜欢数字k的时候,却十分讨厌那些能够整除k而比k小的 ...

  3. NOIP2017提高组 模拟赛13(总结)

    NOIP2017提高组 模拟赛13(总结) 第一题 函数 [题目描述] [输入格式] 三个整数. 1≤t<10^9+7,2≤l≤r≤5*10^6 [输出格式] 一个整数. [输出样例] 2 2 ...

  4. NOIP2017提高组模拟赛 10 (总结)

    NOIP2017提高组模拟赛 10 (总结) 第一题 机密信息 FJ有个很奇怪的习惯,他把他所有的机密信息都存放在一个叫机密盘的磁盘分区里,然而这个机密盘中却没有一个文件,那他是怎么存放信息呢?聪明的 ...

  5. NOIP2017提高组模拟赛 8(总结)

    NOIP2017提高组模拟赛 8(总结) 第一题 路径 在二维坐标平面里有N个整数点,Bessie要访问这N个点.刚开始Bessie在点(0,0)处. 每一步,Bessie可以走到上.下.左.右四个点 ...

  6. NOIP2017提高组模拟赛 9 (总结)

    NOIP2017提高组模拟赛 9 (总结) 第一题 星星 天空中有N(1≤N≤400)颗星,每颗星有一个唯一的坐标(x,y),(1≤x,y ≤N).请计算可以覆盖至少K(1≤K≤N)颗星的矩形的最小面 ...

  7. NOIP2017提高组模拟赛 7(总结)

    NOIP2017提高组模拟赛 7(总结) 第一题 斯诺克 考虑这样一个斯诺克球台,它只有四个袋口,分别在四个角上(如下图所示).我们把所有桌子边界上的整数点作为击球点(除了4个袋口),在每个击球点我们 ...

  8. NOIP2017提高组模拟赛5 (总结)

    NOIP2017提高组模拟赛5 (总结) 第一题 最远 奶牛们想建立一个新的城市.它们想建立一条长度为N (1 <= N <= 1,000,000)的 主线大街,然后建立K条 (2 < ...

  9. NOIP2017提高组模拟赛4 (总结)

    NOIP2017提高组模拟赛4 (总结) 第一题 约数 设K是一个正整数,设X是K的约数,且X不等于1也不等于K. 加了X后,K的值就变大了,你可以重复上面的步骤.例如K= 4,我们可以用上面的规则产 ...

随机推荐

  1. python中random的一些用法

    #(1)随机小数 import random print(random.random())  #随机大于0 且小于1 之间的小数 ''' 0.9441832228391154 ''' print(ra ...

  2. 诊断日志知多少 | DiagnosticSource 在.NET上的应用

    1. 引言 最近为了解决ABP集成CAP时无法通过拦截器启用工作单元的问题,从小伙伴那里学了一招.借助DiagnossticSource,可以最小改动完成需求.关于DiagnosticSource晓东 ...

  3. 轻轻松松学CSS:Grid布局

    网页布局总的来说经历了以下四个阶段: 1.古老的table表格布局,现在基本已被淘汰. 2.float浮动布局(或者position定位布局),借助float.position 等属性等进行布局,这种 ...

  4. VBScript 教程

    VBScript 教程 VB 不区分大小写 变量 普通变量 关键词声明 Dim.Public.Private 赋值动态创建 name = "hello" Option Explic ...

  5. day20 Pyhton学习 面向对象-类与类之间的关系

    一.类与类之间的依赖关系 class Elphant: def __init__(self, name): self.name = name def open(self, ref): print(&q ...

  6. Ubuntu18.04中安装virtualenv和virtualenvwrapper

    1.安装virtualenv和virtualenvwrapper pip3 install virtualenv pip3 install virtualenvwrapper 2.创建目录用来存放虚拟 ...

  7. 第十八章 HTTPS介绍及实战演练

    一.HTTPS介绍 1.概述 为什么需要使用HTTPS,因为HTTP不安全,当我们使用http网站时,会遭到劫持和篡改,如果采用https协议,那么数据在传输过程中是加密的,所以黑客无法窃取或者篡改数 ...

  8. Error:(4, 17) java: 程序包org.junit不存在

    内容:Error:(4, 17) java: 程序包org.junit不存在 场景:运行测试类的时候,IED新建一个自己的项目,并且不用maven的情况下 解决方案:File -> Projec ...

  9. C# 面试前的准备_基础知识点的回顾_04

    1.Session和Cookie的使用区别 很容易回答的就是Session在服务器端,存储的数据可以较大容量,比如我们存一个Table,上千条数据. Cookie保存在客户端,安全系数低,不能放重要的 ...

  10. poj1654 -- Area (任意多边形面积)

    Area Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20444   Accepted: 5567 Description ...