[DTOJ3996]:Lesson5!(DP+拓扑+线段树)
题目描述
“最短的捷径就是绕远路,绕远路就是我最短的捷径”
转眼就$Stage\ X$了,$Stage\ X$的比赛路线可以看做一个$n$个点$m$条边的有向无环图,每条边长度都是$1$。杰洛$\cdot$齐贝林会选择走最长的那一条路径。
迪亚哥$\cdot$布兰度决定摧毁一个城市以及所有关于该城市的边,由于变成恐龙后脑子有点问题,他想要让摧毁后的$Stage$最长路径最短,他想知道要摧毁哪个城市,及摧毁后最长路径的长度,如果有多个城市答案相同,则输出编号最小的那一个。
输入格式
本题包含多组数据,输入第一行一个整数$T$代表数据组数
每组数据第一行两个整数$n,m$表示点数,边数。
每组数据第$2\sim m+1$行每行两个整数$x_i,y_i$表示有一条连接$x_i,y_i$的边。
输出格式
对于每组数据,输出一行两个整数,表示删除的城市编号及删除该城市后最长路径的长度。
样例
样例输入:
1
6 5
1 3
1 4
3 6
3 4
4 5
样例输出:
1 2
数据范围与提示

对于所有数据,满足$T\leqslant 10,1\leqslant n\leqslant 100,000,0\leqslant m\leqslant 500,000$。
题解
$Dijkstra$不能跑最长路!!!
解释一下。
众所周知$Dijkstra$不能跑带负边权的最短路,而跑最长路也就相当于是跑带负边权的最短路,所以它死了……
那么回来考虑这道题。
对于$DAG$,首先想到拓扑。
不妨先跑正反拓扑计算出$dis_s$和$dis_t$分别表示正反拓扑的最长路,思想类似$DP$。
那么边$i$对答案的贡献就是$dis_{s_{i_u}}+dis{t_{i_v}}+1$,删除一个点就相当与删掉了与它相连的边。
快速修改用线段树就好啦。
时间复杂度:$\Theta(m\log n)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct rec{int nxt,to;}e[1000001];
int head[2][100001],cnt;
int n,m;
int a[100001];
int dis[2][100001],sum[100001],tr[400001],in[100001],ou[100001];
pair<int,int> ans;
queue<int> q;
void pre_work()
{
memset(head,0,sizeof(head));
memset(dis,0,sizeof(dis));
memset(sum,0,sizeof(sum));
memset(tr,0,sizeof(tr));
memset(in,0,sizeof(in));
memset(ou,0,sizeof(ou));
memset(a,0,sizeof(a));
cnt=0;ans=make_pair(1,n);
}
void add(bool id,int x,int y)
{
e[++cnt].nxt=head[id][x];
e[cnt].to=y;
head[id][x]=cnt;
}
void pushup(int x){tr[x]=max(tr[L(x)],tr[R(x)]);}
void add(int x,int l,int r,int k)
{
if(l==r)
{
sum[l]++;
if(sum[l]>0)tr[x]=l;
else{sum[l]=0;tr[x]=-1;}
return;
}
int mid=(l+r)>>1;
if(k<=mid)add(L(x),l,mid,k);
else add(R(x),mid+1,r,k);
pushup(x);
}
void del(int x,int l,int r,int k)
{
if(l==r)
{
sum[l]--;
if(sum[l]>0)tr[x]=l;
else{sum[l]=0;tr[x]=-1;}
return;
}
int mid=(l+r)>>1;
if(k<=mid)del(L(x),l,mid,k);
else del(R(x),mid+1,r,k);
pushup(x);
}
int main()
{
freopen("johnny.in","r",stdin);
freopen("johnny.out","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
pre_work();
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(0,x,y);in[y]++;
add(1,y,x);ou[x]++;
}
for(int i=1;i<=n;i++)if(!in[i]){a[++a[0]]=i;q.push(i);}
while(q.size())
{
int x=q.front();q.pop();
for(int i=head[0][x];i;i=e[i].nxt)
{
if(dis[0][e[i].to]<dis[0][x]+1)dis[0][e[i].to]=dis[0][x]+1;
in[e[i].to]--;
if(!in[e[i].to]){a[++a[0]]=e[i].to;q.push(e[i].to);}
}
}
for(int i=1;i<=n;i++)if(!ou[i])q.push(i);
while(q.size())
{
int x=q.front();q.pop();
for(int i=head[1][x];i;i=e[i].nxt)
{
if(dis[1][e[i].to]<dis[1][x]+1)dis[1][e[i].to]=dis[1][x]+1;
ou[e[i].to]--;
if(!ou[e[i].to])q.push(e[i].to);
}
}
for(int i=1;i<=n;i++)add(1,0,n,dis[1][i]);
for(int x=1;x<=n;x++)
{
for(int i=head[1][a[x]];i;i=e[i].nxt)del(1,0,n,dis[0][e[i].to]+dis[1][a[x]]+1);
del(1,0,n,dis[1][a[x]]);
if(tr[1]<ans.second||(ans.second==tr[1]&&a[x]<ans.first))ans=make_pair(a[x],tr[1]);
for(int i=head[0][a[x]];i;i=e[i].nxt)add(1,0,n,dis[0][a[x]]+dis[1][e[i].to]+1);
add(1,0,n,dis[0][a[x]]);
}
printf("%d %d\n",ans.first,ans.second);
}
return 0;
}
rp++
[DTOJ3996]:Lesson5!(DP+拓扑+线段树)的更多相关文章
- Codeforces 675E Trains and Statistic(DP + 贪心 + 线段树)
题目大概说有n(<=10W)个车站,每个车站i卖到车站i+1...a[i]的票,p[i][j]表示从车站i到车站j所需买的最少车票数,求所有的p[i][j](i<j)的和. 好难,不会写. ...
- LightOJ 1085(树状数组+离散化+DP,线段树)
All Possible Increasing Subsequences Time Limit:3000MS Memory Limit:65536KB 64bit IO Format: ...
- BZOJ 1835: [ZJOI2010]base 基站选址(DP,线段树)
可以很容易的写出dp方程: F[i][j]=min(F[l][j-1]+w[l][i])+c[i] (w[i][j]是从l+1到i-1这些点p里,所有满足d[p]+s[p]<d[i] & ...
- Codeforces 671D Roads in Yusland [树形DP,线段树合并]
洛谷 Codeforces 这是一个非正解,被正解暴踩,但它还是过了. 思路 首先很容易想到DP. 设\(dp_{x,i}\)表示\(x\)子树全部被覆盖,而且向上恰好延伸到\(dep=i\)的位置, ...
- LOJ2537 PKUWC2018 Minimax 树形DP、线段树合并
传送门 题意:自己去看 首先可以知道,每一个点都有几率被选到,所以$i$与$V_i$的关系是确定了的. 所以我们只需要考虑每一个值的取到的概率. 很容易设计出一个$DP$:设$f_{i,j}$为在第$ ...
- 洛谷P3928 Sequence2(dp,线段树)
题目链接: 洛谷 题目大意在描述底下有.此处不赘述. 明显是个类似于LIS的dp. 令 $dp[i][j]$ 表示: $j=1$ 时表示已经处理了 $i$ 个数,上一个选的数来自序列 $A[0]$ 的 ...
- CF 463A && 463B 贪心 && 463C 霍夫曼树 && 463D 树形dp && 463E 线段树
http://codeforces.com/contest/462 A:Appleman and Easy Task 要求是否全部的字符都挨着偶数个'o' #include <cstdio> ...
- [Usaco2005 Dec]Cleaning Shifts 清理牛棚 (DP优化/线段树)
[Usaco2005 Dec] Cleaning Shifts 清理牛棚 题目描述 Farmer John's cows, pampered since birth, have reached new ...
- POJ 3171 Cleaning Shifts(DP+zkw线段树)
[题目链接] http://poj.org/problem?id=3171 [题目大意] 给出一些区间和他们的价值,求覆盖一整条线段的最小代价 [题解] 我们发现对区间右端点排序后有dp[r]=min ...
随机推荐
- Hive 教程(二)-认知hive
在大数据领域,hive 的位置非常重要,排名前三的大数据工具为 spark.hive.kafka 什么是hive 在大数据领域有 3 种需求场景:传输.存储.计算: hive 是一个处理海量的结构化数 ...
- ssh连接远程服务器出现Host key验证失败的解决方案
原因可能是云服务器重装过,解决方法是找到提示的know_hosts文件,将报错的那一行的秘钥删掉即可.
- 只读字段(readonly)和常量(const)
1.常量 一个包含不能修改的值的变量,通过const关键字定义.只能在声明的同时赋值 2.只读字段 通过readonly关键字定义. 可以在声明的同时赋值. 对于实例字段,在包含字段声明的类的实例构造 ...
- 关于记录log日志的几种方法
最近在记录日志的时候总结了几种方式: 1.使用log4j2记录 2.使用log4j记录 3.使用logback配置,记录前使用 private final Logger logger = Logge ...
- mysql复习(2)
一.数据定义: SQL数据的定义包括模式的定义.表定义.视图定义和索引的定义. 1.基本的模式定义情况如下表. 2.一个关系数据库管理系统的实例中可以创建多个数据库,一个数据库中可以建立多个模式,一个 ...
- [转载] Java注解
目录 元注解 @Retention @Documented @Target @Inherited @Repeatable 注解语法 ---------------------------------- ...
- SpringBoot布道系列 | 目录汇总 | 2019持续更新ing
SpringBoot 基础教程 | 三大推荐理由 1.文章内容均为原创,结合官方文档和实战经验编写. 2.文章结构经过细致整理,对新人学习更加友好. 3.精选常用技术,不求全面,但求精华!! Spri ...
- Fiddler实现iPhone手机抓包
最近某小程序大火,许多非专业人员也在跃跃欲试,但是在查找自己的session_id的时候卡住了,本文只从技术方面介绍如何通过通过Fiddler来抓取手机的数据,不涉及如何作弊... 1.电脑上安装Fi ...
- Zabbix Agent配置文件详解
# This is a config file for the Zabbix agent daemon (Unix)# To get more information about Zabbix, vi ...
- 白盒测试之JUnit与SpringTest的完美结合
通过白盒的单元测试可以验证程序基本功能的有效性,从而保证整个系统的质量,功在一时,利在千秋.目前80%以上公司后台还是基于java,尤其是后台大量采用Spring框架,我们这里采用Junit和Spri ...