看到区间很容易就能想到线段树。
对于操作2,我们可以建立一棵线段树,线段树的某一个结点表示区间 [l,r] ,那么在图中建立一个结点 u 表示区间 [l,r] ,新建点u 指向 l,l+1,l+2...r的边,权值为 0 。
当得到一个操作 (v,l,r,w) 时,查询一次线段树,把所有符合 [ql,qr]∈[l,r] 的极大区间结点建立一条被 v 指向的边,权值为 w 。这样就能表示 v指向 [l,r] 了。
每一次新建边的操作复杂度是 O(2logn) ,
对于操作3,与操作2类似。得建立两颗线段树来转化,因为区间和对应点列的上下更新是不兼容的,向上是维护最大,向下是维护相同真实值
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
using namespace std;
int n,q,s;
long long inf=1e18;
long long dis[100005*10];
struct node
{
int u,v;
long long w;
node(int uu,int vv,long long ww)
{
u=uu;
v=vv;
w=ww;
}
bool friend operator<(node x,node y)
{
return x.w>y.w;
}
};
vector<node>e[100005*10];
int trd1[100005*4];
int trd2[100005*4];
int cnt;
void build1(int i,int l,int r)
{
if(trd1[i]==0)
trd1[i]=++cnt;
for(int j=l;j<=r;j++)
{
e[j].push_back(node(j,trd1[i],0));
}
if(l==r)
return ;
else
{
int mid=(l+r)/2;
build1(i*2,l,mid);
build1(i*2+1,mid+1,r);
}
}
void build2(int i,int l,int r)
{
if(trd2[i]==0)
trd2[i]=++cnt;
for(int j=l;j<=r;j++)
{
e[trd2[i]].push_back(node(trd2[i],j,0));
}
if(l==r)
return;
else
{
int mid=(l+r)/2;
build2(i*2,l,mid);
build2(i*2+1,mid+1,r);
}
}
void update2(int i,int l,int r,int ql,int qr,int u,long long w)
{
if(l==ql && r==qr)
{
e[u].push_back(node(u,trd2[i],w));
}
else
{
int mid=(l+r)/2;
if(mid>=qr)
{
update2(i*2,l,mid,ql,qr,u,w);
}
else if(mid<ql)
{
update2(i*2+1,mid+1,r,ql,qr,u,w);
}
else
{
update2(i*2,l,mid,ql,mid,u,w);
update2(i*2+1,mid+1,r,mid+1,qr,u,w);
}
}
}
void update1(int i,int l,int r,int ql,int qr,int u,long long w)
{
if(l==ql && r==qr)
{
e[trd1[i]].push_back(node(trd1[i],u,w));
}
else
{
int mid=(l+r)/2;
if(mid>=qr)
{
update1(i*2,l,mid,ql,qr,u,w);
}
else if(mid<ql)
{
update1(i*2+1,mid+1,r,ql,qr,u,w);
}
else
{
update1(i*2,l,mid,ql,mid,u,w);
update1(i*2+1,mid+1,r,mid+1,qr,u,w);
}
}
}
int main()
{
while(~scanf("%d%d%d",&n,&q,&s))
{
cnt=n;
memset(trd1,0,sizeof(trd1));
memset(trd2,0,sizeof(trd2));
for(int i=0;i<100000*10;i++)
dis[i]=inf,e[i].clear();
build1(1,1,n);
build2(1,1,n);
while(q--)
{
int f;
scanf("%d",&f);
if(f==1)
{
int u,v;
long long w;
scanf("%d%d%lld",&u,&v,&w);
e[u].push_back(node(u,v,w));
}
else if(f==2)
{
int u,l,r;
long long w;
scanf("%d%d%d%lld",&u,&l,&r,&w);
update2(1,1,n,l,r,u,w);
}
else if(f==3)
{
int u,l,r;
long long w;
scanf("%d%d%d%lld",&u,&l,&r,&w);
update1(1,1,n,l,r,u,w);
}
}
//dijistra
dis[s]=0;
priority_queue<node> pq;
pq.push(node(s,0,0));
while(!pq.empty())
{
node cur=pq.top();
pq.pop();
int tu=cur.u;
int len=e[tu].size();
//cout<<len<<endl;
for(int i=0;i<len;i++)
{
int v=e[tu][i].v;
long long tw=e[tu][i].w;
if(dis[v]>dis[tu]+tw)
{
dis[v]=dis[tu]+tw;
pq.push(node(v,0,dis[v]));
}
}
}
for(int i=1;i<=n;i++)
{
if(dis[i]==inf)
{
printf("-1 ");
}
else
{
printf("%lld ",dis[i]);
}
}
printf("\n");
}
}