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. 系统架构设计:平滑发布和ABTesting

    平滑发布的介绍 背景 单位的云办公相关系统没有成熟的平滑发布方案,导致每一次发布都是直接发布,dll文件或配置文件的变更会引起站点的重启. 云办公系统的常驻用户有10000+,即使短短半分多钟,也会收 ...

  2. TP5上传图片到七牛云,并且删除七牛云的图片

    一,通过composer 下载七牛云 sdk composer require qiniu/php-sdk 二,手动下载七牛云sdk 1,https://developer.qiniu.com/kod ...

  3. unix中的线程池技术详解

    •线程池就是有一堆已经创建好了的线程,当有新的任务需要处理的时候,就从这个池子里面取一个空闲等待的线程来处理该任务,当处理完成了就再次把该线程放回池中,以供后面的任务使用,当池子里的线程全都处理忙碌状 ...

  4. spring框架中配置mysql8.0需要注意的地方(转载)

    8.0以后的mysql很强大,但是配置写法出现了不同 主要原因是时区不同,mysql默认用的是国外某个地方的时区,而我们要用的话用使用东八时区,这是中国统一时区. 装载自https://blog.cs ...

  5. selenium常用操作学习笔记

    一,弹窗处理(推荐文章:https://blog.csdn.net/huilan_same/article/details/52298460) selenium提供switch_to方法定位弹窗的对话 ...

  6. 【值得收藏】C语言入门基础知识大全!从C语言程序结构到删库跑路!

    01 C语言程序的结构认识 用一个简单的c程序例子,介绍c语言的基本构成.格式.以及良好的书写风格,使小伙伴对c语言有个初步认识. 例1:计算两个整数之和的c程序: #include main() { ...

  7. 【学习笔记】扩展卢卡斯定理 exLucas

    引子 求 \[C_n^m\ \text{mod}\ p \] 不保证 \(p\) 是质数. 正文 对于传统的 Lucas 定理,必须要求 \(p\) 是质数才行.若 \(p\) 不一定是质数,则需要扩 ...

  8. go 结构体初始化

    package main import "fmt" type Dog struct { Name string } func TestStruct() { // 方式1 //var ...

  9. css中伪元素before或after中content的特殊用法attr【转】

    [原文]https://segmentfault.com/a/1190000002750033 CSS中主要的伪元素有四个:before/after/first-letter/first-line,在 ...

  10. Linux文件元数据和节点表结构

    文件元数据 一块硬盘的分区可以认为有两部分组成,保存元数据的成为节点表,用来保存属性等. 元数据中有个小指针,指向数据存放的实际空间. 元数据(Metadata) 又称中介数据.中继数据,为描述数据的 ...