【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\)次机会的最小花费

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

\(\begin{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.cost\end{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;
} 

原文地址:https://www.cnblogs.com/ShuraEye/p/11622663.html

时间: 2024-10-22 04:31:19

【XSY2278】【HDU5669】the Red Sun(线段树+dijkstra)的相关文章

[CF787D]遗产(Legacy)-线段树-优化Dijkstra(内含数据生成器)

Problem 遗产 题目大意 给出一个带权有向图,有三种操作: 1.u->v添加一条权值为w的边 2.区间[l,r]->v添加权值为w的边 3.v->区间[l,r]添加权值为w的边 求st点到每个点的最短路 Solution 首先我们思考到,若是每次对于l,r区间内的每一个点都执行一次加边操作,不仅耗时还耗空间. 那么我们要想到一个办法去优化它.一看到lr区间,我们就会想到线段树对吧. 没错啦这题就是用线段树去优化它. 首先我们建一棵线段树,然后很容易想到,我们只需要把这一棵线段树当做

【BZOJ3073】[Pa2011]Journeys 线段树+堆优化Dijkstra

[BZOJ3073][Pa2011]Journeys Description Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路.Seter保证一条道路不会修建两次,也保证不会有一个国家与自己之间有道路. Seter好不容易建好了所有道路

【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

HDU5669 Road 分层最短路+线段树建图

分析:(官方题解) 首先考虑暴力,显然可以直接每次O(n^2) ?的连边,最后跑一次分层图最短路就行了. 然后我们考虑优化一下这个连边的过程 ,因为都是区间上的操作,所以能够很明显的想到利用线段树来维护整个图, 连边时候找到对应区间,把线段树的节点之间连边.这样可以大大缩减边的规模,然后再跑分层图最短路就可以了. 但是这样建图,每一次加边都要在O(logn)个线段树节点上加边,虽然跑的非常快,但是复杂度仍然是不科学的. 为了解决边的规模的问题,开两棵线段树,连边时候可以新建一个中间节点,在对应区

BZOJ 2725 Violet 6 故乡的梦 堆优化Dijkstra+线段树

题目大意:给定一张带权无向图和起点S.终点T,每次询问如果某条边被删掉那么从S到T的最短路是多少 数据范围2?105 注意样例错了 第二个输出应该是6不是5 首先搞出从S到T的任意一条最短路 然后对于一条边(x,y),如果不在最短路径上,预处理出S到x的最短路以及何时离开选定的最短路径S′,以及y到T的最短路以及何时进入选定的最短路径T′ 然后删掉S′到T′路径上的边的话就可以用一条S?S′?x?y?T′?T的路径代替 用线段树维护即可 时间复杂度O((n+m+q)logn) #include

POJ2777-Count Color 线段树

题目传送门:http://poj.org/problem?id=2777 Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 45259   Accepted: 13703 Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of

poj 2777 count color 线段树

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

pku 2777(经典线段树染色问题)

Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 41202   Accepted: 12458 Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d