• 【XSY2278】【HDU5669】the Red Sun(线段树+dijkstra)


    (Description)

    给定一张 (N) 个点的图, 点的标号为 (1)(n) . 我们进行 (M) 次连边, 每次连边可以描述为 (a) (b) (c) (d) (w:)

    for i = a to b do
    
        for j = c to d do
    
             Add_Edge(i,j,w)        
    

    (Add_Edge(i,j,w)) 表示从点 (i) 向点 (j) 连一条费用为 (w) 的双向边.

    求点 (1) 到点 (n) 的最小花费.

    为了降低难度, 我们有 (K) 次机会可以消除某条边的花费.


    (Input)

    第一行一个数 (T) , 表示测试数据组数. 出于某种原因, (T=1 .)

    第二行三个数 (N,M,K) .

    接下来 (M) 行, 每行 (5) 个数 (a,b,c,d,w) , 意义如题目描述所示.


    (Output)

    一行一个数, 为最小的花费.

    如果点 (1) 与点 (n) 不连通, 输出 "Yww is our red sun!" .


    (Sample Input)

    1
    5 3 0
    1 2 4 5 42
    5 5 4 4 468
    1 1 3 3 335


    (Sample Output)

    42


    (HINT)

    (T=1,1≤N≤5×10^4,1≤M≤10^4,0≤K≤10,1≤w≤10^3)


    (Source)

    练习题 树4-1-线段树


    思路

    思路可以参考【XSY2434】【CF787D】遗产(也是我自己写的)

    基本上思路一致

    也是一个最短路的题目,使用线段树优化

    对于每两个([a,b])([c,d])区间间的连边,我们设一个中间点(x),将([a,b])连向(x),再由(x)连向([c,d])

    我们现在开始考虑怎么求最短路

    我们都知道要使用(dijkstra)

    但是多了一个限制条件我们有 (K) 次机会可以消除某条边的花费

    于是我们显然想到了(dp)

    (dis[i][j])表示到达(i)节点,用了(j)次机会的最小花费

    于是我们可以得到状转方程:

    (egin{cases}dis[now.x][v]=now.cost+val[i]&dis[now.x][v]>now.cost+val[i]\dis[now.x+1][v]=now.cost&now.x<k且dis[now.x+1][v]>now.costend{cases})

    我们就可以快乐地实现最短路啦


    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=400010,M=2000010;
    int n,m,k,rt1,rt2,cnt=0;
    int lc1[N],rc1[N],lc2[N],rc2[N];
    int dis[15][N];
    bool vis[15][N];
    int w;
    int to[M<<1],nxt[M<<1],val[M<<1],head[N];
    int nodetot=0;
    struct edge
    {
        int u,cost,x;
        bool operator < (const edge & e)const
        {
            return cost>e.cost;
        }
    };
    void add(int u,int v,int wi)
    {
        to[++cnt]=v;
        val[cnt]=wi;
        nxt[cnt]=head[u];
        head[u]=cnt;
    }
    int build1(int l,int r)
    {
        if(l==r)return l;
        int now=++nodetot;
        int mid=(l+r)>>1;
        lc1[now-n]=build1(l,mid);
        add(lc1[now-n],now,0);
        rc1[now-n]=build1(mid+1,r);
        add(rc1[now-n],now,0);
        return now;
    }
    int build2(int l,int r)
    {
        if(l==r)return l;
        int now=++nodetot;
        int mid=(l+r)>>1;
        lc2[now-n]=build2(l,mid);
        add(now,lc2[now-n],0);
        rc2[now-n]=build2(mid+1,r);
        add(now,rc2[now-n],0);
        return now;
    }
    void modify1(int k,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)
        {
    		add(k,nodetot,w);
            return ;
        }
        int mid=(l+r)>>1;
        if(ql<=mid)modify1(lc1[k-n],l,mid,ql,qr);
        if(qr>mid)modify1(rc1[k-n],mid+1,r,ql,qr);
    }
    void modify2(int k,int l,int r,int ql,int qr) 
    {
        if(ql<=l&&r<=qr)
        {
    		add(nodetot,k,0);
            return ;	
        }
        int mid=(l+r)>>1;
        if(ql<=mid)modify2(lc2[k-n],l,mid,ql,qr);
        if(qr>mid)modify2(rc2[k-n],mid+1,r,ql,qr);
    }
    priority_queue<edge>qu;
    void dijkstra()
    {
        memset(dis,127,sizeof(dis));
        dis[0][1]=0;
        qu.push((edge){1,0,0});
        edge now;
        while(!qu.empty())
        {
            now=qu.top();
            qu.pop();
            if(vis[now.x][now.u])continue;
            vis[now.x][now.u]=1;
            for(int i=head[now.u];i;i=nxt[i])
            {
                int v=to[i];
                if(dis[now.x][v]>now.cost+val[i]&&!vis[now.x][v])
                {
                    dis[now.x][v]=now.cost+val[i];
                    qu.push((edge){v,dis[now.x][v],now.x});
                }
                if(now.x<k&&!vis[now.x+1][v]&&dis[now.x+1][v]>now.cost)
                {
                    dis[now.x+1][v]=now.cost;
                    qu.push((edge){v,dis[now.x+1][v],now.x+1});
                }
            }
        }
    }
    int main()
    {
        scanf("%d",&n);
        scanf("%d %d %d",&n,&m,&k);
        int a,b,c,d;
        nodetot=n;
        rt1=build1(1,n);
        rt2=build2(1,n);
        while(m--)
        {   
            scanf("%d %d %d %d %d",&a,&b,&c,&d,&w);
            nodetot++;//中间点
            modify1(rt1,1,n,a,b);modify2(rt2,1,n,c,d);
            nodetot++;//中间点
            modify1(rt1,1,n,c,d);modify2(rt2,1,n,a,b);
        }
        dijkstra();
        int ans=dis[0][0];
        for(int i=0;i<=k;i++)ans=min(ans,dis[i][n]);
        if(ans==dis[0][0])puts("Yww is our red sun!");
        else printf("%d",ans);
        return 0; 
    } 
    
  • 相关阅读:
    Linux命令之 文件归档管理
    C#总结项目《影院售票系统》编写总结完结篇
    C#总结项目《影院售票系统》编写总结三
    C#中MD5加密
    C#中的序列化与反序列化
    C#总结项目《影院售票系统》编写总结二
    C#总结项目《影院售票系统》编写总结一
    java多线程与线程并发四:线程范围内的共享数据
    java多线程与线程并发三:线程同步通信
    java多线程与线程并发二:线程互斥
  • 原文地址:https://www.cnblogs.com/ShuraEye/p/11622663.html
Copyright © 2020-2023  润新知