• 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 disydisx+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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
  • 相关阅读:
    在Qt中使用SQLite数据库
    git回退到某个提交
    C++-容器:string使用介绍(非常全面,详细)
    Python+unittest接口自动化测试
    OpenGL原理与实践——核心模式(六):光照贴图、光源分类以及多光源场景主要源码实现
    模版代码:Express 中间件快速入门
    whistle启动时,输入命令w2 start报:w2 start‘w2‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。
    【21天学习挑战赛】折半查找
    2023年,新手如何玩赚互联网项目?
    css样式在弹性盒元素在必要的时候拆行
  • 原文地址:https://blog.csdn.net/Mr_wuyongcong/article/details/125452601