【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序+线段树了.而对于第二个操作,考虑再维护一 ...
随机推荐
- 未能正确加载包“Microsoft.Data.Entity.Design.Package.MicrosoftDataEntityDesignPackage
本文出处:http://blog.sina.com.cn/s/blog_6fe3efa301016i64.html vs 2005 ,vs 2008, vs 2010,安装后有时出现这个错误(我的机器 ...
- repeater 根据输入 返回汉字
page repeater <asp:Repeater ID="r_scoreCount" runat="server"> <HeaderTe ...
- Java集合系列:-----------03ArrayList源码分析
上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解ArrayLi ...
- Vs2013中通过Nuget添加不同版本jQuery
vs2013中如果直接更新jQuery则是2X的版本,为了兼容IE浏览器的,一般都是希望使用jQuery1.x版本的jQuery,则可在调出Nuget的控制台,在控制台输入(此例子是下载jQuery ...
- cpu负载和利用率
理解Linux系统负荷 linux里的CPU负载
- Linux 信号详解四(pause,alarm)
pause函数 --将进程置为可中断睡眠状态,然后它调用内核函数schedule(),使linux进程调度器找到另一个进程来运行. --pause使调用者进程挂起,知道一个信号被捕获. alarm函数 ...
- Theano3.2-练习之数据集及目标函数介绍
来自http://deeplearning.net/tutorial/gettingstarted.html#gettingstarted 一.下载 在后续的每个学习算法上,都需要下载对应的文档,如果 ...
- spring boot 自动部署方案
现在主流的自动部署方案大都是基于Docker的了,但传统的自动部署方案比较适合中小型公司,下面的方案就是比较传统的自动部署方案. 1.为什么需要自动部署 基于微服务的架构,自动部署显得非常重要.因为每 ...
- 化茧成蝶,开源NetWorkSocket通讯组件
前言 前后历时三年,期间大量参考.Net Framework和Asp.net MVC源代码,写写删删再重构,组件如今更新到V1.5.x了.从原来的丑小鸭,变成今天拥有稳定和强大的tcp协议支持基础层, ...
- [译]用AngularJS构建大型ASP.NET单页应用(二)
原文地址:http://www.codeproject.com/Articles/808213/Developing-a-Large-Scale-Application-with-a-Single 客 ...