在qbxt某营集体做的
题解里以及外地OIer基本上都写两颗线段树的
而我们六安的OIer神TM思维一致——只用一颗线段树,类似于一维分层图的思想,第二层上与第一层相对应的结点的编号是第一层结点编号+NUM,而且貌似比分颗的思维正常一点,因为满足lson=k<<1,rson=k<<1|1,和一般的线段树相似度高。
至于为什么要分颗或分层,容易想明白树边(辅助边)必须是双向的(因为要用祖先结点的出入信息),但如果不分颗或分层的话求出来最短路不很明显是0了吗QwQ
所以分层的话父向子应是一层,子向父应在另一层,两层之间通过叶节点相连
另外关于叶结点的处理问题,YoOXiii和Pride205是把原图第i结点投影到树上第i+n结点(n为原图结点个数)
这个详见他们的代码(其实我也没仔细研究清楚他们的处理方法),这里不偷了(偷窃犯罪w),要看自己找
由于我和他们不坐一块,想思路时没有交流,所以我没有这样写,我是把第一层按照一般线段树的编号建,这样容易一点。然后把原图结点直接向叶子结点映射即可(开一个pos数组)(才知道szsz46也是这么写的,原来六安OIer的思维同步性不随空间改变QwQ)
然后......
上代码吧
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#define NUM 1000000
#define maxn 100005<<5
//这两个范围要调好
#define int long long
using namespace std;
typedef long long ll;
inline void input(ll &x){
ll ans=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ans=ans*10+c-48;
c=getchar();
}
x=ans*f;
}
inline void output(ll x){
if(x<0)x=-x,putchar('-');
if(x>9)output(x/10);
putchar(x%10+48);
}
inline void writeln(ll x){
output(x);
putchar('\n');
}
int n,m,s,head[maxn],c[maxn],pos[maxn],vis[maxn],dis[maxn],cnt;
//pos:题中结点在树上的编号
struct edge{
int v,w,next;
}e[maxn];
struct node{
int dis,u;
bool operator<(const node &x)const{return x.dis<dis;}
};
inline void add(int u,int v,int w){
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
// cout<<u<<' '<<v<<' '<<w<<endl;
}
inline void build(int k,int l,int r){
if(l==r){
pos[l]=k;
add(k+NUM,k,0);
add(k,k+NUM,0);
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
add(k<<1,k,0);
add(k<<1|1,k,0);
add(k+NUM,(k<<1)+NUM,0);//调了一个小时:加括号;在括号外加NUM而不是给k加NUM
add(k+NUM,(k<<1|1)+NUM,0);
}
inline void add(int k,int l,int r,int xl,int xr,int from,int w,int opt){
if(xl<=l&&r<=xr){
if(opt==2)add(from,k+NUM,w);
else if(opt==3)add(k,from,w);
return;
}
int mid=(l+r)>>1;
if(xl<=mid)add(k<<1,l,mid,xl,xr,from,w,opt);
if(xr>=mid+1)add(k<<1|1,mid+1,r,xl,xr,from,w,opt);
}
priority_queue<node> q;
inline void dijkstra(){
s=pos[s];
q.push((node){0,s});
dis[s]=0;
while(!q.empty()){
int x=q.top().u;
q.pop();
if(vis[x])continue;
vis[x]=1;
for(int i=head[x];i!=-1;i=e[i].next){
int y=e[i].v;
if(!vis[y]&&dis[y]>dis[x]+e[i].w){
dis[y]=dis[x]+e[i].w;
q.push((node){dis[y],y});//想不到吧,这一行打错使我调了半个小时
}
}
}
s<<=1;
if(s>=1)dijkstra();
}
signed main(){
memset(head,-1,sizeof(head));
memset(dis,127,sizeof(dis));
memset(vis,0,sizeof(vis));
input(n);input(m);input(s);
build(1,1,n);
for(int i=1;i<=m;i++){
int opt;
input(opt);
if(opt==1){
int u,v,w;
input(u);input(v);input(w);
add(pos[u],pos[v],w);
}
else if(opt==2){
int u,l,r,w;
input(u);input(l);input(r);input(w);
add(1,1,n,l,r,pos[u],w,opt);
}
else if(opt==3){
int u,l,r,w;
input(u);input(l);input(r);input(w);
add(1,1,n,l,r,pos[u],w,opt);
}
}
dijkstra();
// for(int i=1;i<=4*n;i++)cout<<i<<' '<<dis[i]<<endl;
for(int i=1;i<=n;i++)output(dis[pos[i]]<=1e15?dis[pos[i]]:-1),putchar(' ');
}