bzoj3073Journeys(线段树优化最短路)

这里写图片描述

这里还是一道涉及到区间连边的问题。

如果暴力去做,那么就会爆炸

那么这时候就需要线段树来优化了。

因为是双向边

所以需要两颗线段树来分别对应入边和出边

QwQ然后做就好了咯

不过需要注意的是,这个边数的大小不好掌握,以后碰到这种题还是要仔细算一算的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define pa pair<int,int>

using namespace std;

inline int read()
{
   int x=0,f=1;char ch=getchar();
   while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
   while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
   return x*f;
}

const int maxn = 5000010;
const int maxm = 9e6+1e2;

int f[2*maxn],g[2*maxn];
int leaf[maxn];
int point[maxn],nxt[maxm],to[maxm],val[maxm];
int cnt,s,t;
int dis[maxn],vis[maxn];
int tmp;
int n,m;

priority_queue<pa,vector<pa>,greater<pa> > q;

void addedge(int x,int y,int w)
{
    nxt[++cnt]=point[x];
    to[cnt]=y;
    val[cnt]=w;
    point[x]=cnt;
}

void insert(int x,int y,int w)
{
    addedge(x,y,w);
    addedge(y,x,w);
}

void build(int root,int l,int r)
{
    if (l==r)
    {
        leaf[l]=++tmp;
        f[root]=tmp;
        return;
    }
    f[root]=++tmp;
    int mid = (l+r) >> 1;
    build(2*root,l,mid);
    build(2*root+1,mid+1,r);
    addedge(f[root],f[2*root],0);
    addedge(f[root],f[2*root+1],0); 
}

void build1(int root,int l,int r)
{
    if (l==r)
    {
        g[root]=leaf[l];
        return;
    }
    g[root]=++tmp;
    int mid = (l+r) >> 1;
    build1(2*root,l,mid);
    build1(2*root+1,mid+1,r);
    addedge(g[2*root],g[root],0);
    addedge(g[2*root+1],g[root],0); 
}

void update(int root,int l,int r,int x,int y,int p)
{
    if (x<=l && r<=y)
    {
        addedge(p,f[root],1);
        return;
    }
    int mid = (l+r) >> 1;
    if (x<=mid)  update(2*root,l,mid,x,y,p);
    if (y>mid) update(2*root+1,mid+1,r,x,y,p);
}

void update1(int root,int l,int r,int x,int y,int p)
{
    if (x<=l && r<=y)
    {
        addedge(g[root],p,0);
        return;
    }
    int mid = (l+r) >> 1;
    if (x<=mid)  update1(2*root,l,mid,x,y,p);
    if (y>mid) update1(2*root+1,mid+1,r,x,y,p);
}

void dijkstra(int s)
{
    memset(dis,127/3,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[leaf[s]]=0;
    q.push(make_pair(0,leaf[s]));
    while (!q.empty())
    {
        //cout<<1<<endl;
        int x=q.top().second;
        q.pop();
        if (vis[x]) continue;
        vis[x]=1;
        for (int i=point[x];i;i=nxt[i])
        {
            int p = to[i];
            if (dis[p]>dis[x]+val[i])
            {
                dis[p]=dis[x]+val[i];
                q.push(make_pair(dis[p],p));
             } 
        }
     } 
}

int main()
{
  n=read(),m=read(),s=read();
  build(1,1,n);
  build1(1,1,n);
  for (int i=1;i<=m;i++)
  {
     int l,r,l1,r1;
     l=read(),r=read();
     l1=read(),r1=read();
     int cnt1=++tmp;
     int cnt2=++tmp;
     update(1,1,n,l,r,cnt1);
     update1(1,1,n,l1,r1,cnt1);
     update(1,1,n,l1,r1,cnt2);
     update1(1,1,n,l,r,cnt2);
  }
  dijkstra(s);
  for (int i=1;i<=n;i++)
  {
     printf("%d",dis[leaf[i]]);
     if (i!=n) printf("\n");
  }
  return 0;
}
阅读更多
文章标签: c++
个人分类: 线段树 最短路
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭