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. Java知识系统回顾整理01基础02面向对象02属性

    一.根据实例给出"属性"的定义 一个英雄有姓名,血量,护甲等等状态 这些状态就叫做一个类的属性 二.属性的类型 属性的类型可以是基本类型,比如int整数,float 浮点数 也可以 ...

  2. IDEA中创建父子工程与maven打包Springboot聚合工程报错程序包不存在问题处理

    公司新项目需使用java技术栈,便使用IDEA搭建了一个多SpringBoot项目的聚合工程,因为初次使用,遇到了很多问题,maven打包时各种报错,在网上查了好多终于解决了,为巩固记忆,特作此记录. ...

  3. Java虚拟机系列——检视阅读

    Java虚拟机系列--检视阅读 参考 java虚拟机系列 入门掌握JVM所有知识点 2020重新出发,JAVA高级,JVM JVM基础系列 从 0 开始带你成为JVM实战高手 Java虚拟机-垃圾收集 ...

  4. 如何让矢量瓦片配图神器maputnik支持 geoserver

    关键词:maputnik.geoserver.矢量地图.矢量瓦片.mapbox.mapboxgl.地图配图.地图配色 一直想搞一个类似百度.高德地图那样的矢量地图配图工具 百度个性化地图配图工具: 高 ...

  5. 多测师讲解htm_L标题标签001_高级讲师 肖sir

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>百 ...

  6. Rust之路(1)

    [未经书面许可,严禁转载]-- 2020-10-09 -- 正式开始Rust学习之路了! 思而不学则罔,学而不思则殆.边学边练才能快速上手,让我们先来个Hello World! 但前提是有Rust环境 ...

  7. SpringBoot常见注解

    0.前言 这篇文章介绍的 Spring/SpringBoot 常用注解基本已经涵盖你工作中遇到的大部分常用的场景.对于每一个注解我都说了具体用法,掌握搞懂,使用 SpringBoot 来开发项目基本没 ...

  8. 在shell中截取心仪的字符串

    file=/dir1/dir2/dir3/my.file.txt ${file#*/} 去掉左边 ${file##*/} 去掉左边最后一个 ${file%/*} 去掉右边 ${file%%/*} 去掉 ...

  9. 使用python编写正逆序乘法表

    # 99乘法表 # 顺序 for i in range(1,10): n = 1 while n <= i: print('{}x{}={}'.format(n,i,n*i),end=' ') ...

  10. v-model数据绑定分析

    v-model数据绑定分析 v-model是Vue提供的指令,其主要作用是可以实现在表单<input>.<textarea>及<select>等元素以及组件上创建双 ...