HDU 5669 Road(线段树建树)(分层图最短路)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5669

【分析】线段树建树+分层图最短路

#include <cstdio>
#include <map>
#include <algorithm>
#include <vector>
#include <iostream>
#include <set>
#include <queue>
#include <string>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
typedef pair<int,int>pii;
typedef long long LL;
const int N=6e5+5;
const int mod=1e9+7;
int n,m,s,k,t,cnt,idl[N<<1],idr[N<<1];
bool vis[N][11];
LL d[N][11];
vector<pii>edg[N];
void buildl(int rt,int l,int r)
{
    idl[rt]=++cnt;
    if(l==r)return ;
    int m=l+r>>1;
    buildl(rt<<1,l,m);
    buildl(rt<<1|1,m+1,r);
    edg[idl[rt<<1]].push_back(make_pair(idl[rt],0));
    edg[idl[rt<<1|1]].push_back(make_pair(idl[rt],0));
}
void buildr(int rt,int l,int r)
{
    idr[rt]=++cnt;
    if(l==r)return ;
    int m=l+r>>1;
    buildr(rt<<1,l,m);
    buildr(rt<<1|1,m+1,r);
    edg[idr[rt]].push_back(make_pair(idr[rt<<1],0));
    edg[idr[rt]].push_back(make_pair(idr[rt<<1|1],0));
}
void pre(int rt,int l,int r)
{
    if(l==r)
    {
        edg[l].push_back(make_pair(idl[rt],0));
        edg[idr[rt]].push_back(make_pair(l,0));
        return;
    }
    int m=l+r>>1;
    pre(rt<<1,l,m);
    pre(rt<<1|1,m+1,r);
}
void addl(int rt,int l,int r,int L,int R,int w){
    if(L<=l&&r<=R){
        edg[idl[rt]].push_back(make_pair(cnt,w));
        return;
    }
    int mid=(l+r)/2;
    if(L<=mid)addl(rt*2,l,mid,L,R,w);
    if(R>mid)addl(rt*2+1,mid+1,r,L,R,w);
}
void addr(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        edg[cnt].push_back(make_pair(idr[rt],0));
        return;
    }
    int mid=(l+r)/2;
    if(L<=mid)addr(rt*2,l,mid,L,R);
    if(R>mid)addr(rt*2+1,mid+1,r,L,R);
}
struct man{
    int v;
    int c;
    LL w;
    bool operator<(const man &e)const{
        return w>e.w;
    }
};
priority_queue<man>q;
void dij(int s){
    memset(d,-1,sizeof d);memset(vis,0,sizeof vis);
    d[s][0]=0;
    q.push(man{s,0,0});
    while(!q.empty()){
        int u=q.top().v,c=q.top().c;q.pop();
        if(vis[u][c])continue;
        vis[u][c]=1;
        for(int i=0;i<edg[u].size();++i){
            int v=edg[u][i].first,w=edg[u][i].second;
            if(!vis[v][c]&&(d[v][c]==-1||d[v][c]>d[u][c]+w)){
                d[v][c]=d[u][c]+w;
                q.push(man{v,c,d[v][c]});
            }
            if(c<k){
                if(!vis[v][c+1]&&(d[v][c+1]==-1||d[v][c+1]>d[u][c])){
                    d[v][c+1]=d[u][c];
                    q.push(man{v,c+1,d[v][c+1]});
                }
            }
        }
    }
}
int main()
{
    int x,y,w,l,r;
    int T;
    scanf("%d",&T);
    while(T--){
        for(int i=0;i<N;i++)edg[i].clear();
        scanf("%d%d%d",&n,&m,&k);
        cnt=n;
        buildl(1,1,n);
        buildr(1,1,n);
        pre(1,1,n);
        while(m--)
        {
            ++cnt;
            scanf("%d%d%d%d%d",&x,&y,&l,&r,&w);
            addl(1,1,n,x,y,w);
            addr(1,1,n,l,r);
            cnt++;           //此处要注意
            addl(1,1,n,l,r,w);
            addr(1,1,n,x,y);
        }
        dij(1);
        LL ans=1000000000000;
        for(int i=0;i<=k;i++)ans=min(ans,d[n][i]);
        if(ans!=-1)printf("%lld\n",ans);
        else puts("CreationAugust is a sb!");
    }
    return 0;
}
时间: 2024-08-20 13:14:57

HDU 5669 Road(线段树建树)(分层图最短路)的相关文章

Codeforces 787D. Legacy 线段树优化建图+最短路

output standard output Rick and his co-workers have made a new radioactive formula and a lot of bad guys are after them. So Rick wants to give his legacy to Morty before bad guys catch them. There are n planets in their universe numbered from 1 to n.

CF786B Legacy(线段树优化建图+最短路)

在qbxt某营集体做的 题解里以及外地OIer基本上都写两颗线段树的 而我们六安的OIer神TM思维一致--只用一颗线段树,类似于一维分层图的思想,第二层上与第一层相对应的结点的编号是第一层结点编号+NUM,而且貌似比分颗的思维正常一点,因为满足lson=k<<1,rson=k<<1|1,和一般的线段树相似度高. 至于为什么要分颗或分层,容易想明白树边(辅助边)必须是双向的(因为要用祖先结点的出入信息),但如果不分颗或分层的话求出来最短路不很明显是0了吗QwQ 所以分层的话父向子应

POJ 1177/HDU 1828 picture 线段树+离散化+扫描线 轮廓周长计算

求n个图矩形放下来,有的重合有些重合一部分有些没重合,求最后总的不规则图型的轮廓长度. 我的做法是对x进行一遍扫描线,再对y做一遍同样的扫描线,相加即可.因为最后的轮廓必定是由不重合的线段长度组成的,这样理论上是对的 要注意处理高度相同的线段,把底边优先处理(在代码里就是f标记为1的线段),因为若是一个矩形的底边和另一个矩形的上边重合,则这个轮廓肯定不能算 不过POJ和HDU的数据好像都比较弱,我没进行上面的细节处理也AC了,不过一个很简单的数据就会不对,所以还是要处理一下才是真正正确的代码 我

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

【bzoj4276】[ONTAK2015]Bajtman i Okr?g?y Robin 线段树优化建图+费用流

题目描述 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢走c[i]元.作为保安,你在每一段长度为1的时间内最多只能制止一个强盗,那么你最多可以挽回多少损失呢? 输入 第一行包含一个正整数n(1<=n<=5000),表示强盗的个数. 接下来n行,每行包含三个正整数a[i],b[i],c[i](1<=a[i]<b[i]<=5000,1<=c[i]

HDU 1828 Picture 线段树+扫描线

题意:给你一些矩形的左上角点的坐标和右下角点的坐标,求周长并 最显而易见的思路就是对于x轴和y轴做两次扫描线,对于负数的坐标进行离散化.每次增加的值是线段变化量的绝对值.具体写法和求面积并的差不多. #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define lson rt << 1 , l , m

HDU 1542 Atlantis(线段树扫描线)

http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6788    Accepted Submission(s): 2970 Problem Description There are several ancient Greek

【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路.Seter保证不会有一个国家与自己之间有道路. Seter好不容易建好了所有道路,他现在在位于P号的首都.Seter想知道P号国家到任意一个国家最少需要经过几条道路.当然,Se

hdu 1542 Atlantis(线段树&amp;扫描线&amp;面积并)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6386    Accepted Submission(s): 2814 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i