【BZOJ-3832】Rally 拓扑序 + 线段树 (神思路题!)
3832: [Poi2014]Rally
Time Limit: 20 Sec Memory Limit: 128 MBSec Special Judge
Submit: 168 Solved: 84
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
1 3
1 4
3 6
3 4
4 5
Sample Output
HINT
Source
Solution
神思路!
直接求最长路径的方法是拓扑排序后DP
那么这道题先建立源汇,那么最长路径就是S-->T的最长路
实际上对于一条边<u,v>经过这条边的最长路就是S-->u的最长+<u,v>+v-->T的最长
所以定义f[x][0]和f[x][1]表示S到x的最长,x到T的最长,那么我们对一条边<u,v>他的权值定义为f[x][0]+f[v][1]
那么这个图的最长路径就转化的所有边的边权的最大值
现在就用一个数据结构去维护这些信息,支持删除,添加,最大
显然可以用堆,也可以用线段树
假设开始所有点都在T集中
按照拓扑序删点,并把该点加入S集中
把这个点有关的入边删掉,此时的最大值就是删当前点的答案,再把出边加入即可
Code
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<stack>
using namespace std;
void Freopen() {freopen("flower.in","r",stdin); freopen("flower.out","w",stdout);}
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXM 1000010
#define MAXN 500010
int N,M;
struct EdgeNode{int to,next;}edge[MAXM],road[MAXM];
int head[MAXN],cnt,last[MAXN],tot;
void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
void AddRoad(int u,int v) {tot++; road[tot].next=last[u]; last[u]=tot; road[tot].to=v;}
int topo[MAXN],tp,ind[MAXN],visit[MAXN],f[MAXN][];
void TopoSort()
{
int S=,T=N;
stack<int>st;
for (int i=S; i<=T; i++) if (!ind[i]) st.push(i),topo[++tp]=i;
while (!st.empty())
{
int now=st.top(); st.pop(); visit[now]=;
for (int i=head[now]; i; i=edge[i].next)
{
ind[edge[i].to]--;
if (!ind[edge[i].to]) st.push(edge[i].to),topo[++tp]=edge[i].to;
}
}
// printf("tp=%d\n",tp);
// for (int i=1; i<=tp; i++) printf("%d\n",topo[i]);
}
void GetLongestRoad()
{
for (int i=; i<=N; i++)
{
int now=topo[i];
f[now][]=max(f[now][],);
for (int j=head[now]; j; j=edge[j].next)
f[edge[j].to][]=max(f[edge[j].to][],f[now][]+);
}
for (int i=N; i>=; i--)
{
int now=topo[i];
f[now][]=max(f[now][],);
for (int j=head[now]; j; j=edge[j].next)
f[now][]=max(f[edge[j].to][]+,f[now][]);
}
}
struct SegmentTreeNode{int l,r,maxx,num;}tree[MAXN<<];
inline void Update(int now) {tree[now].maxx=max(tree[now<<].maxx,tree[now<<|].maxx);}
void BuildTree(int now,int l,int r)
{
tree[now].l=l,tree[now].r=r;
if (l==r) return;
int mid=(l+r)>>;
BuildTree(now<<,l,mid);
BuildTree(now<<|,mid+,r);
Update(now);
}
void Change(int now,int loc,int D)
{
int l=tree[now].l,r=tree[now].r;
if (l==r)
{tree[now].num+=D; tree[now].maxx=tree[now].num>? l:-; tree[now].num=max(tree[now].num,); return;}
int mid=(l+r)>>;
if (loc<=mid) Change(now<<,loc,D); else Change(now<<|,loc,D);
Update(now);
}
int Query(int now,int L,int R)
{
int l=tree[now].l,r=tree[now].r;
if (L<=l && R>=r) return tree[now].maxx;
int mid=(l+r)>>,re=-0x7fffffff;
if (L<=mid) re=max(re,Query(now<<,L,R));
if (R>mid) re=max(re,Query(now<<|,L,R));
return re;
}
int MaxLen,Pos;
int main()
{
// Freopen();
N=read(),M=read();
for (int x,y,i=; i<=M; i++)
x=read(),y=read(),AddEdge(x,y),AddRoad(y,x),ind[y]++;
TopoSort();
GetLongestRoad();
BuildTree(,,N);
MaxLen=0x7fffffff;
for (int i=; i<=N; i++) Change(,f[i][],);
for (int i=; i<=N; i++)
{
int now=topo[i];
Change(,f[now][],-);
for (int j=last[now]; j; j=road[j].next)
Change(,f[road[j].to][]+f[now][],-);
if (Query(,,N)<MaxLen) MaxLen=Query(,,N),Pos=now;
Change(,f[now][],);
for (int j=head[now]; j; j=edge[j].next)
Change(,f[now][]+f[edge[j].to][],);
}
printf("%d %d\n",Pos,MaxLen-);
return ;
}
【BZOJ-3832】Rally 拓扑序 + 线段树 (神思路题!)的更多相关文章
- 【BZOJ】4311: 向量(线段树分治板子题)
题解 我们可以根据点积的定义,垂直于原点到给定点构成的直线作一条直线,从正无穷往下平移,第一个碰到的点就是答案 像什么,上凸壳哇 可是--动态维护上凸壳? 我们可以离线,计算每个点能造成贡献的一个询问 ...
- [BZOJ 2653] middle(可持久化线段树+二分答案)
[BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...
- codevs1228 (dfs序+线段树)
1228 苹果树 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 在卡卡的房子外面,有一棵苹果树.每年的春天,树上总会结 ...
- bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论
题目大意 1.将x到当前根路径上的所有点染成一种新的颜色: 2.将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根: 3.查询以x为根的子树中所有点权值的平均值. 分析 原题codec ...
- DFS序+线段树(bzoj 4034)
题目链接 题目就不多说了. 本题目,可以用dfs序+线段树做:题目给定了一棵树,树上节点告诉了权值.我们可以先将这棵树进行dfs将一棵树变成线性结构:如图 变成这样后,然后就可以用线段树. 操作1:也 ...
- BZOJ 3252题解(贪心+dfs序+线段树)
题面 传送门 分析 此题做法很多,树形DP,DFS序+线段树,树链剖分都可以做 这里给出DFS序+线段树的代码 我们用线段树维护到根节点路径上节点权值之和的最大值,以及取到最大值的节点编号x 每次从根 ...
- Educational Codeforces Round 6 E dfs序+线段树
题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...
- 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心
3252: 攻略 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 339 Solved: 130[Submit][Status][Discuss] D ...
- Codeforces 343D Water Tree(DFS序 + 线段树)
题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...
随机推荐
- 用sql查询当天,一周,一个月的数据
用sql查询当天,一周,一个月的数据 数据查询,不管在网站还是在系统,都很常见,下文是介绍最常见的以日期查询的语句 select * from ShopOrder where datediff(w ...
- HTML5商城开发三 jquery 星星评分插件
展示:
- Linux shell的输入输出
echo --echo命令可以显示文本行或变量,或者把字符串输入到文件 --echo [option] string -e 解析转义字符 例如:echo -e "nimenhao\nasfd ...
- struts2 异常处理3板斧
板斧1:找不到action的错误 在struts.xml中参考如下配置 <struts> ... <package name="default" namespac ...
- spring 3.2.x + struts2 + mybatis 3.x + logback 整合配置
与前面的一篇mybatis 3.2.7 与 spring mvc 3.x.logback整合 相比,只是web层的MVC前端框架,从spring mvc转换成struts 2.x系列,变化并不大 一. ...
- asp中的md5/sha1/sha256算法收集
对于asp这种古董级的技术,这年头想找一些有用的资料已经不容易了,下面是一些常用的加密算法: md5 (将以下代码另存为md5.inc) <% Private Const BITS_TO_A_B ...
- JAVA CDI 学习(4) - @Alternative/@Default/@Any & Extension
前面几节学习到的CDI内容,基本上都是hard-code,以硬编码的方式在代码里指定注入类型,这并非依赖注入的本意,依赖注入的优势之一在于“解耦”,这一节我们将学习如何利用配置来动态注入的类型及属性初 ...
- flask+sqlite3+echarts2+ajax数据可视化--静态图
结构: /www | |-- /static | | | |-- echarts.js(当然还有echarts原dist目录下的文件(夹)) | |-- /templates | | | |-- in ...
- 前端见微知著番外篇:Bitbucket进行代码管控
说道代码管控,一般都会提到TFS.Git等,但是在这里我们将要用到Bitbucket,其实其操作方式和Git基本上一样,但是和TFS则有很大的不同了.但是原理基本上都是一致的. 这里我不会过多的涉及到 ...
- STM32-外部中断,没有硬件干扰就是快乐
一:触发方式 STM32 的外部中断是通过边沿来触发的,不支持电平触发: 二:外部中断分组 STM32 的每一个GPIO都能配置成一个外部中断触发源,STM32 通过根据引脚的序号不同将众多中断触发源 ...