题意:
1.求S到所有点的最短路
2.三种加有向边的方式
(1)点->点(2)点到区间(3)区间到点
解:
1、暴力的话边加不完,
2、区间操作-->考虑线段树
3、建立两棵线段树
入树和出树
void build(ll &x,ll l,ll r,ll op){
x=++tot;
if(l==r){
if(op==0){
ind_0[l]=x;
}else{
ind_1[l]=x;add(ind_0[l],ind_1[l],0);add(ind_1[l],ind_0[l],0);
}
return ;
}
ll mid=(l+r)>>1;
build(ls[x],l,mid,op);build(rs[x],mid+1,r,op);
if(!op){
add(ls[x],x,0);add(rs[x],x,0);
}else{
add(x,ls[x],0);add(x,rs[x],0);
}
}
(1)*****注意出树的叶子节点要和出树对应的叶子节点 要将无向边缩成一个点*****
(2)***边的数量要足够*****
(3)最后求的就是出树的叶子节点的dis值
加边:
1:u->v,加边<A的叶子节点u,B的叶子节点v,w><A的叶子节点u,B的叶子节点v,w>
2:u->[l,r],加边<A的叶子节点u,{B树中[l,r]区间对应的节点集合},w><A的叶子节点u,{B树中[l,r]区间对应的节点集合},w>
3:[l,r]->v,加边<{A树中[l,r]区间对应的节点集合},B树的叶子节点v,w>
[1]
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<queue>
#define en '\n'
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll maxn=8*(100000+10);
ll n,Q,s;
ll ls[maxn],rs[maxn],ind_0[maxn],ind_1[maxn];
ll cnt=0;
ll rt[10];
ll head[maxn];
ll read(){
ll tem;scanf("%I64d",&tem);return tem;
}
struct node{
ll v,nxt,w;
}edge[maxn<<3];
void add(ll x,ll y,ll w){
edge[++cnt]=(node){y,head[x],w};head[x]=cnt;
}
void padd(ll x,ll l,ll r,ll ql,ll qr,ll goal ,ll op,ll w){
if(l>=ql and r<=qr){
if(!op){
add(x,goal,w);
}
else add(goal,x,w);
return ;
}
ll mid=(l+r)>>1;
if(ql<=mid){
padd(ls[x],l,mid,ql,qr,goal,op,w);
}
if(qr>mid){
padd(rs[x],mid+1,r,ql,qr,goal,op,w);
}
}
ll tot=0;
void build(ll &x,ll l,ll r,ll op){
x=++tot;
if(l==r){
if(op==0){
ind_0[l]=x;
}else{
ind_1[l]=x;add(ind_0[l],ind_1[l],0);add(ind_1[l],ind_0[l],0);
}
return ;
}
ll mid=(l+r)>>1;
build(ls[x],l,mid,op);build(rs[x],mid+1,r,op);
if(!op){
add(ls[x],x,0);add(rs[x],x,0);
}else{
add(x,ls[x],0);add(x,rs[x],0);
}
}
priority_queue< pair<ll,ll> >q;
bool vis[maxn];
ll dis[maxn];
void dj(){
mem(dis,0x3f);dis[ind_0[s]]=0;q.push({0,ind_0[s]});
while(q.size()){
ll now=q.top().second;q.pop();if(vis[now])continue;vis[now]=1;
for(ll i=head[now];i;i=edge[i].nxt){
ll y=edge[i].v;
if(dis[y]>dis[now]+edge[i].w){
dis[y]=dis[now]+edge[i].w;
q.push({-dis[y],y});
}
}
}
}
signed main()
{
#ifdef local
freopen("input2.txt","r",stdin);
#endif
cin>>n>>Q>>s;
cnt=0;
build(rt[0],1,n,0);build(rt[1],1,n,1);
while(Q--){
ll f,x,y,w;f=read();
if(f==1){
x=read(),y=read(),w=read();
add(ind_0[x],ind_1[y],w);
}
else if(f==2){
ll now=read();
x=read(),y=read(),w=read();
add(ind_0[now],++tot,w);
padd(rt[1],1,n,x,y,tot,1,0);
}
else{
ll now=read();
x=read(),y=read(),w=read();
padd(rt[0],1,n,x,y,++tot,0,0);add(tot,ind_1[now],w);
}
}
dj();
for(ll i=1;i<=n;i++){
if(dis[ind_1[i]]==inf){
cout<<-1<<' ';
}else
cout<<dis[ind_1[i]]<<' ';
}
return 0;
}
参考:[1]Blackops CF 787D Legacy(线段树思想构图+最短路)