P2483 【模板】k 短路 / [SDOI2010] 魔法猪学院
题目传送门
思路:
这道题问最多有多少条路径并且这些路径长度和要小于等于
介于它增加了数据使得我不得不使用可持久化合并堆对它进行优化。
我们对于反图跑一边最短路,其中
我们用小根堆来维护这些非树边,每次取出权值最小的边。当前取出的边的起点是点
-
在小根堆中加一个一 个
u 为起点并且权值大于等于取出来边的权值的边。 -
在小跟堆中加入一个这条边结尾的节点在左偏树中祖先连的非树边。
AC code
#include <bits/stdc++.h>
using namespace std;
#define pii pair<double,int>
const double ep = 1e-8;
const int N = 10005;
const int M = 200005;
int n,m;
double E;
struct node{
int id,v;
double w;
};
vector<node>road[N],rroad[N];
double dist[N];
int root[N];
namespace LT{
struct point{
int lson,rson,last;
int dist;
double val;
}tr[M * 20];
int cnt = 0;
int create(double v,int last)
{
int u = ++cnt;
tr[u].val = v;
tr[u].last = last;
tr[u].dist = tr[u].lson = tr[u].rson = 0;
return cnt;
}
int cop(int id)
{
int u = ++cnt;
tr[u] = tr[id];
return u;
}
int merge(int x,int y)
{
if(x == 0 || y == 0)
{
return x | y;
}
if(tr[x].val > tr[y].val)
{
swap(x,y);
}
int u = cop(x);
tr[u].rson = merge(tr[u].rson,y);
if(tr[tr[u].lson].dist < tr[tr[u].rson].dist)
{
swap(tr[u].lson,tr[u].rson);
}
tr[u].dist = tr[tr[u].rson].dist + 1;
return u;
}
void insert(int &rt,double val,int last)
{
rt = merge(create(val,last),rt);
}
}
using namespace LT;
priority_queue<pii,vector<pii>,greater<pii> >q;
void dij()
{
for(int i = 0;i < N;i++)
{
dist[i] = 1e9;
}
dist[n] = 0;
q.push((pii){0.0,n});
while(!q.empty())
{
int u = q.top().second;
double len = q.top().first;
q.pop();
if(dist[u] != len)
{
continue;
}
for(int i = 0;i < rroad[u].size();i++)
{
int v = rroad[u][i].v;
double l = rroad[u][i].w;
if(dist[v] > dist[u] + l)
{
dist[v] = dist[u]+ l;
q.push((pii){dist[v],v});
}
}
}
}
int f[N];
int st[N];
bool vis[N];
int top;
bool line[M];//当前边是不是树边
void dfs(int u)
{
st[++top] = u;
vis[u] = true;
for(int i = 0;i < rroad[u].size();i++)
{
int v = rroad[u][i].v;
double l = rroad[u][i].w;
if(dist[v] == dist[u] + l && vis[v] == false)
{
line[rroad[u][i].id] = true;
f[v] = u;
dfs(v);
}
}
}
void build()
{
for(int i = 1;i<=top;i++)
{
int u = st[i];
root[u] = root[f[u]];
for(int i = 0;i < road[u].size();i++)
{
int id = road[u][i].id;
int v = road[u][i].v;
double w = road[u][i].w;
if(!line[id] && dist[v] != dist[0])
{
insert(root[u],dist[v] + w - dist[u],v);
}
}
}
}
int kshort()
{
int cnt = 1;
E-=dist[1];
priority_queue<pii,vector<pii>,greater<pii> >q;
q.push((pii){dist[1] + tr[root[1]].val,root[1]});
while(!q.empty())
{
double len = q.top().first;
int u = q.top().second;
q.pop();
if(len -ep>E)break;
E-=len - ep;
cnt++;
int l = tr[u].lson;
int r = tr[u].rson;
int top = tr[u].last;
if(root[top])
{
q.push((pii){len + tr[root[top]].val,root[top]});
}
if(l)
{
q.push((pii){len + tr[l].val - tr[u].val,l});
}
if(r)
{
q.push((pii){len + tr[r].val - tr[u].val,r});
}
}
return cnt;
}
int main()
{
scanf("%d%d%lf",&n,&m,&E);
for(int i = 1;i <= m;i++)
{
int u,v;
double w;
scanf("%d%d%lf",&u,&v,&w);
if(u == n)//特判u为n的路
{
i--;
m--;
continue;
}
road[u].push_back((node){i,v,w});
rroad[v].push_back((node){i,u,w});//建反图
}
dij();//反图跑最短路
dfs(n);//建最短路树
build();//建左偏树
printf("%d\n",kshort());
return 0;
}