zoukankan      html  css  js  c++  java
  • 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("
    ");
      }
      return 0;
    }
    
  • 相关阅读:
    Leetcode(11)-盛最多水的容器
    Leetcode(10)-正则表达式匹配
    Leetcode(104)-二叉树的最大深度
    Leetcode(106)-从中序与后序遍历序列构造二叉树
    Ubuntu多系统安装注意事项
    openstack安装、卸载与启动
    基于数据存储管理的带有头尾指针的双向链表创建实例
    JQuery右键菜单contextMenu插件
    jQuery判断当前浏览器类型
    后台获取登录的IP地址
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10160915.html
Copyright © 2011-2022 走看看