线段树优化建图
线段树优化建图
例题:CF786B
题目意思差不多就是对于区间进行连边,边有边权,然后求起点到其它点的最短路。
主要优化思路就是线段树。我们考虑建两棵线段树,每个节点维护的区间就存着对应区间的连边信息。一颗内向一颗外向,两棵树本质相同,都是维护节点的信息,所以说两棵树每对对应的叶子节点都要互相连一条边权位 0 的边,如图:
这幅图中的所有边边权均为 0。显然()。然后考虑如何进行连边操作。容易发现连边其实都应该是右边的线段树连向左边的线段树(内向树连向外向树),这样才能保证从点出发能经过所连的边。假如说从外向树连向内向树,那么可能出现无法到达的情况。感觉还是比较显然的()
具体的连边:
其中点连点怎么连都行()
tips:处理节点的时候不要把
连完边之后就正常跑 Dij 即可~
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define pii pair<int,int>
#define ls (root << 1)
#define rs (root << 1 | 1)
#define mid ((l + r) >> 1)
const int MAX = 1e5 + 5;
const int mod = 998244353;
const int INF = 0x7fffffff;
const int p = 4e5+1;
inline int read(){
int x=0,y=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-')y=-1;
for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+(c^48);
return x*y;
}
int n,Q,s,dis[MAX<<3],leaf[MAX];
struct Day_Tao {int v,w;};
vector<Day_Tao>e[MAX<<3];
inline void build(int l,int r,int root)
{
if(l==r) return leaf[l]=root,void();
e[root].push_back({ls,0}),e[root].push_back({rs,0});
e[ls+p].push_back({root+p,0}),e[rs+p].push_back({root+p,0});
build(l,mid,ls),build(mid+1,r,rs); return ;
}
void update(int l,int r,int root,int ql,int qr,int v,int w,int op)
{
if(r<ql||l>qr) return ;
if(ql<=l&&r<=qr)
{
if(op&1) e[root+p].push_back({v,w});
else e[v+p].push_back({root,w}); return ;
}
update(l,mid,ls,ql,qr,v,w,op),update(mid+1,r,rs,ql,qr,v,w,op); return ;
}
priority_queue<pii,vector<pii>,greater<pii>>q;
bool vis[MAX<<3];
signed main()
{
// freopen(".in","r",stdin),freopen(".out","w",stdout);
n=read(),Q=read(),s=read();
build(1,n,1);
while(Q--)
{
int op=read(),v=read(),l=read(),r=read(),w;
if(op==1) e[leaf[v]].push_back({leaf[l],r});
else w=read(),update(1,n,1,l,r,leaf[v],w,op);
}
for(int i=1;i<=n;i++) e[leaf[i]].push_back({leaf[i]+p,0}),e[leaf[i]+p].push_back({leaf[i],0});
memset(dis,0x3f,sizeof(dis)),dis[leaf[s]+p]=0,q.push({0,leaf[s]+p});
while(!q.empty())
{
int u=q.top().second;q.pop();
if(!vis[u])
{
vis[u]=1;
for(Day_Tao i:e[u])
{
int v=i.v,w=i.w;
if(dis[v]>dis[u]+w) dis[v]=dis[u]+w,q.push({dis[v],v});
}
}
}
for(int i=1;i<=n;i++) if(dis[leaf[i]]==0x3f3f3f3f3f3f3f3f) printf("-1 ");else printf("%lld ",dis[leaf[i]]);
return 0;
}