CF786B Legacy
https://www.luogu.com.cn/problem/CF786B
线段树优化建图
对于区间\([l,r]\),可以用线段树中的节点优化建图
对于从外面指向指定区间的边,它只能往下转移
例:
如果存在\(v\rightarrow [l,r]\),那么一定存在\(v\rightarrow [s,t]([s,t] \in [l,r])\)
因此需要边\([l,r]\rightarrow [s,t]\)才能实现转移
对于从指定区间指向外面的边,它只能往上转移
例:
如果\([l,r]\rightarrow v\),那么一定存在\([s,t]\rightarrow v ([s,t] \in[l,r])\)
因此需要边\([s,t]\rightarrow [l,r]\)才能实现转移
因为两种不同的情况需要两种类型的附加图,所以我们需要两颗线段树维护
然后跑最短路就好了
\(Code:\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#define N 100005
#define ll long long
#define pr pair<ll,int>
#define mp make_pair
#define INF 123456789987654321
using namespace std;
int cnt,t;
priority_queue<pr,vector<pr>,greater<pr> >q;
struct edge
{
int v,cost;
edge (int xx=0,int yy=0)
{
v=xx,cost=yy;
}
};
vector<edge>e[N << 3];
int n,Q,s,rt1,rt2,opt,v,u,l,r,ls[N << 2],rs[N << 2];
ll w;
ll dis[N << 2];
bool vis[N << 2];
void add(int x,int y,int z)
{
e[x].push_back(edge(y,z));
}
void build(int &p,int l,int r)
{
if (l==r)
{
p=l;
return;
}
p=++cnt;
int mid=(l+r) >> 1;
build(ls[p],l,mid);
build(rs[p],mid+1,r);
add(p,ls[p],0),add(p,rs[p],0);
}
void build_2(int &p,int l,int r)
{
if (l==r)
{
p=l;
return;
}
p=++cnt;
int mid=(l+r) >> 1;
build_2(ls[p],l,mid);
build_2(rs[p],mid+1,r);
add(ls[p],p,0),add(rs[p],p,0);
}
void change(int p,int l,int r,int x,int y)
{
if (l>y||r<x)
return;
if (x<=l&&r<=y)
{
add(v,p,w);
return;
}
int mid=(l+r) >> 1;
change(ls[p],l,mid,x,y);
change(rs[p],mid+1,r,x,y);
}
void change_2(int p,int l,int r,int x,int y)
{
if (l>y||r<x)
return;
if (x<=l&&r<=y)
{
add(p,v,w);
return;
}
int mid=(l+r) >> 1;
change_2(ls[p],l,mid,x,y);
change_2(rs[p],mid+1,r,x,y);
}
int main()
{
scanf("%d%d%d",&n,&Q,&s);
cnt=n;
build(rt1,1,n);
build_2(rt2,1,n);
for (int i=1;i<=Q;i++)
{
scanf("%d",&opt);
switch (opt)
{
case 1:
scanf("%d%d%lld",&v,&u,&w);
add(v,u,w);
break;
case 2:
scanf("%d%d%d%lld",&v,&l,&r,&w);
t=1;
change(rt1,1,n,l,r);
break;
case 3:
scanf("%d%d%d%lld",&v,&l,&r,&w);
t=2;
change_2(rt2,1,n,l,r);
break;
}
}
for (int i=1;i<=cnt;i++)
dis[i]=INF,vis[i]=false;
dis[s]=0;
q.push(mp(0,s));
while (!q.empty())
{
pr Ru=q.top();
q.pop();
#define u Ru.second
if (vis[u])
continue;
vis[u]=true;
for (vector<edge>::iterator it=e[u].begin();it!=e[u].end();++it)
{
if (dis[u]+it->cost<dis[it->v])
{
dis[it->v]=dis[u]+it->cost;
q.push(mp(dis[it->v],it->v));
}
}
}
for (int i=1;i<=n;i++)
printf("%lld ",(dis[i]!=INF)?dis[i]:(-1));
putchar('\n');
return 0;
}