IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> P2483-[模板]k短路/[SDOI2010]魔法猪学院【主席树堆】 -> 正文阅读

[数据结构与算法]P2483-[模板]k短路/[SDOI2010]魔法猪学院【主席树堆】

正题

题目链接:https://www.luogu.com.cn/problem/P2483


题目大意

给出一个 n n n个点 m m m条边的一张带权有向图,求一个最大的 k k k使得 1 ~ n 1\sim n 1n的前 k k k短路径长度和不超过 E E E

2 ≤ n ≤ 5000 , 1 ≤ m ≤ 2 × 1 0 5 , 1 ≤ E ≤ 1 0 7 2\leq n\leq 5000,1\leq m\leq 2\times 10^5,1\leq E\leq 10^7 2n5000,1m2×105,1E107


解题思路

我们先把从 n n n出发的一棵反向最短路树跑出来,注意这里的最短路树是真的一棵树,我们从 D A G DAG DAG中随便提一些边出来构成一棵树,以 n n n为根。

然后考虑我们将其他的路径中不在树上的路径拿出来,那么这些边肯定满足前一条边的终点 t t t肯定在后一条边起点 s s s的子树中。

如果我们能确定这样一个有序的边集就相当于确定了这样一条唯一的路径。

然后考虑一条边 ( x , y , w ) (x,y,w) (x,y,w)的边权视为 d i s y ? d i s x + w dis_y-dis_x+w disy??disx?+w,这样最终的路径长度就是 d i s 1 dis_1 dis1?加上这些边的权值和。

然后考虑怎么去扩展我们的方案,假设我们现在的边集 E E E的倒数第一个和最后一个分别是 ( x ′ , y ′ , w ′ ) , ( x , y , w ) (x',y',w'),(x,y,w) (x,y,w),(x,y,w)

那么我们有两种扩展方式:

  1. 在最后加一条边,这条边的起点一点得是 y y y y y y的祖先。
  2. 替换最后一条边,这条边必须是起点是 y ′ y' y或其祖先中恰好比当前这条边权大的边。

因为有重复边权,我们还是给每条边一个具体的顺序。

然后用堆维护最后两条边的状态就好了,主席树维护每个点其祖先的所有出边的一棵权值线段树。


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=2e5+10,M=N<<5;
const double eps=1e-8;
struct edge{
	int x,y;
	bool ban;
	double w;
}e[N];
struct node{
	int to,next,w;
}a[N];
int n,m,tot,ans,ls[N],ban[N],fa[N],rt[N];
double f[N],k;bool v[N];map<int,int> u[N];
vector<int> T[N],ot[N];
priority_queue<pair<double,int> >_q;
priority_queue<pair<double,pair<int,int> > >q;
struct SegTree{
	int cnt,w[M],ls[M],rs[M];
	int Change(int x,int L,int R,int pos){
		int p=++cnt;w[p]=w[x]+1;
		if(L==R)return p;int mid=(L+R)>>1;
		if(pos<=mid)ls[p]=Change(ls[x],L,mid,pos),rs[p]=rs[x];
		else rs[p]=Change(rs[x],mid+1,R,pos),ls[p]=ls[x];
		return p;
	}
	int Ask(int x,int L,int R,int k){
		if(k>R||!w[x])return 0;
		if(L==R)return L;int mid=(L+R)>>1;
		if(k>mid)return Ask(rs[x],mid+1,R,k);
		int ans=Ask(ls[x],L,mid,k);
		if(!ans)ans=Ask(rs[x],mid+1,R,k);
		return ans;
	}
}S;
void addl(int x,int y,int w){
	a[++tot].to=y;
	a[tot].next=ls[x];
	ls[x]=tot;a[tot].w=w;
	return;
}
void dij(){
	for(int i=1;i<n;i++)f[i]=1e100;
	_q.push(mp(0,n));
	while(!_q.empty()){
		int x=_q.top().second;_q.pop();
		if(v[x])continue;v[x]=1;
		for(int i=ls[x];i;i=a[i].next){
			int y=a[i].to;
			if(f[x]+e[a[i].w].w<f[y]){
				f[y]=f[x]+e[a[i].w].w;
				ban[y]=a[i].w;fa[y]=x;
				_q.push(mp(-f[y],y));
			}
		}
	}
	return;
}
bool cmp(edge x,edge y)
{return x.w<y.w;}
void dfs(int x){
	for(int i=0;i<ot[x].size();i++)
		rt[x]=S.Change(rt[x],1,m,ot[x][i]);
	for(int i=0;i<T[x].size();i++)
		rt[T[x][i]]=rt[x],dfs(T[x][i]);
	return;
}
void solve(){
	int x=S.Ask(rt[1],1,m,0);
	q.push(mp(-f[1]-e[x].w,mp(1,x)));
	while(!q.empty()){
		double w=-q.top().first;
		int x=q.top().second.first;
		int y=q.top().second.second;
		q.pop();
		if(k+eps<w){ans++,ans--;return;}
		k-=w;ans++;
		int p=S.Ask(rt[e[y].y],1,m,1);
		if(p)q.push(mp(-w-e[p].w,mp(e[y].y,p)));
		p=S.Ask(rt[x],1,m,y+1);
		if(p)q.push(mp(-w+e[y].w-e[p].w,mp(x,p)));
	}
}
int main()
{
//	freopen("P2483_3.in","r",stdin);
	scanf("%d%d%lf",&n,&m,&k);
	for(int i=1;i<=m;i++){
		scanf("%d%d%lf",&e[i].x,&e[i].y,&e[i].w);
		addl(e[i].y,e[i].x,i);
	}
	dij();
	if(k<f[1])return puts("0")&0;k-=f[1];ans++;
	for(int i=1;i<n;i++)e[ban[i]].ban=1;
	for(int i=1;i<n;i++)T[fa[i]].push_back(i);
	for(int i=1;i<=m;i++)
		if(!e[i].ban&&e[i].x!=n)
			e[i].w=f[e[i].y]+e[i].w-f[e[i].x];
		else swap(e[i],e[m]),m--,i--;
	sort(e+1,e+1+m,cmp);
	for(int i=1;i<=m;i++)ot[e[i].x].push_back(i);
	dfs(n);solve();
	printf("%d\n",ans);
	return 0;
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-06-29 19:19:23  更:2022-06-29 19:24:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/19 13:55:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码