HDU5669
(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
Catalog
Problem:传送门
原题目描述在最下面。
给你n个点,m组边: a, b ,c ,d ,w.表示点[a,b]与点[c,d]有一条权值为w的无向边。求1-n的最短路。
有k次把一条边权值变为0的魔法。
Solution:
线段树优化建边。对于魔法就在求最短路的时候再加一维处理。
dp[i][j]表示到点i用了j次魔法的最短路径长度。
dp[u][t+1] = min(dp[u][t+1],dp[v][t]);//t+1<=k
\]
AC_Code:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
typedef long long LL;
const LL INF = 0x3f3f3f3f;
const int MXN = 6e5 + 5;
const int MXE = 4e6 + 6;
int n, m, k;
int inde;
vector<int>vs, vt;
struct lp{
    int v, nex;
    int w;
    friend bool operator < (const lp &a,const lp &b) {
        return a.w > b.w;
    }
}cw[MXE], A, B;
int head[MXN], tot;
int dis[MXN][12];
int vis[MXN][12];
void add_edge(int u,int v,int w) {
    cw[++tot].v = v; cw[tot].w = w; cw[tot].nex = head[u];
    head[u] = tot;
}
int seg[MXN][2];
void build(int id,int l,int r,int rt) {
    seg[rt][id] = ++inde;
    if(l == r) {
        if(id) add_edge(seg[rt][id], l, 0);
        else add_edge(l, seg[rt][id], 0);
        return;
    }
    int mid = (l + r) >> 1;
    build(id, l, mid, lson); build(id, mid + 1, r, rson);
    if(id) {
        add_edge(seg[rt][id], seg[lson][id], 0); add_edge(seg[rt][id], seg[rson][id], 0);
    }else {
        add_edge(seg[lson][id], seg[rt][id], 0); add_edge(seg[rson][id], seg[rt][id], 0);
    }
}
void query(int id,int L,int R,int l,int r,int rt) {
    if(L <= l && r <= R) {
        if(id) vs.push_back(seg[rt][id]);
        else vt.push_back(seg[rt][id]);
        return;
    }
    int mid = (l + r) >> 1;
    if(L > mid) query(id, L, R, mid+1, r, rson);
    else if(R <= mid) query(id,L,R,l,mid,lson);
    else {
        query(id,L,mid,l,mid,lson); query(id,mid+1,R,mid+1,r,rson);
    }
}
void dij() {
    for(int i = 1; i <= inde; ++i) {
        for(int j = 0; j <= k; ++j) {
            dis[i][j] = INF;
            vis[i][j] = 0;
        }
    }
    dis[1][0] = 0;
    A.v = 1; A.w = 0; A.nex = 0;
    priority_queue<lp> Q;
    Q.push(A);
    while(!Q.empty()) {
        B = Q.top(); Q.pop();
        int u = B.v, t = B.nex;
        if(vis[u][t]) continue;
        vis[u][t] = 1;
        for(int i = head[u]; ~i; i = cw[i].nex) {
            int v = cw[i].v;
            if(dis[v][t] > dis[u][t] + cw[i].w) {
                dis[v][t] = dis[u][t] + cw[i].w;
                A.v = v; A.w = dis[v][t]; A.nex = t;
                Q.push(A);
            }
            if(t < k && dis[v][t+1] > dis[u][t]) {
                dis[v][t+1] = dis[u][t];
                A.v = v; A.w = dis[v][t+1]; A.nex = t+1;
                Q.push(A);
            }
        }
    }
    int ans = INF;
    for(int i = 0; i <= k; ++i) ans = min(ans, dis[n][i]);
    if(ans >= INF) printf("CreationAugust is a sb!\n");
    else printf("%d\n", ans);
}
int main() {
    int tim;
    scanf("%d", &tim);
    while(tim --) {
        scanf("%d%d%d", &n, &m, &k);
        int a, b, c, d, w;
        memset(head, -1, sizeof(head));
        tot = -1;
        inde = n;
        build(1, 1, n, 1); build(0, 1, n, 1);
        for(int i = 0, ta, tb; i < m; ++i) {
            scanf("%d%d%d%d%d", &a, &b, &c, &d, &w);
            vs.clear(); vt.clear();
            query(1,c,d,1,n,1); query(0,a,b,1,n,1);
            ta = vs.size(); tb = vt.size();
            for(int i = 0; i < tb; ++i) {
                for(int j = 0; j < ta; ++j) {
                    add_edge(vt[i], vs[j], w);
                }
            }
            vs.clear(); vt.clear();
            query(1,a,b,1,n,1); query(0,c,d,1,n,1);
            a = vs.size(); b = vt.size();
            for(int i = 0; i < b; ++i) {
                for(int j = 0; j < a; ++j) {
                    add_edge(vt[i], vs[j], w);
                }
            }
        }
        dij();
    }
    return 0;
}
Problem Description:
HDU5669的更多相关文章
- HDU5669 Road 分层最短路+线段树建图
		
分析:(官方题解) 首先考虑暴力,显然可以直接每次O(n^2) 的连边,最后跑一次分层图最短路就行了. 然后我们考虑优化一下这个连边的过程 ,因为都是区间上的操作,所以能够很明显的想到利用线段树来维 ...
 
随机推荐
- php操作redis--有序集合(sorted set)篇
			
常用函数:zAdd,zRange,zRem,zCard等. 应用场景:类似集合,可以提供一个优先级的参数来为成员排序,如:分数 连接 $redis = new Redis(); $redis-> ...
 - 创建一个wx.App的子类
			
#_author:来童星#date:2019/12/20#创建一个wx.App的子类import wxclass App(wx.App): #初始化方法 def OnInit(self): frame ...
 - Java中链接MS SQL 数据库用法详解
			
一.第一种方法: 使用JDBC-ODBC的桥方式 JDBC-ODBC桥连接器是用JdbcOdbc.class 和一个用于访问ODBC驱动程序的本地库实现的,对于Windows平台,该本地库是一个动态链 ...
 - Android中的Service 与 Thread 的区别
			
很多时候,你可能会问,为什么要用 Service,而不用 Thread 呢,因为用 Thread 是很方便的,比起 Service 也方便多了,下面我详细的来解释一下. 1). Thread:Thre ...
 - CTSC2019
			
(upd:随机立方体AC) 太菜了只会部分分.以后慢慢补坑吧…… 随机立方体: 30分: 正常人都能想到的的转移状态(我的确是弱智),从大往小填数,记录有多少个极大值点和三个方向上各占了多少.转移可以 ...
 - [7.22NOIP模拟测试7]方程的解 题解(扩展欧几里得)
			
Orz 送分比较慷慨的一道题,疯狂特判能拿不少分. 对于$a>0,b>0$的情况: 用exgcd求出方程通解,然后通过操作得到最小正整数解和最大正整数解 他们以及他们之间的解满足等差数列性 ...
 - (转)Openfire 中SASL的认证方式之:PLAIN,DIGEST-MD5,anonymous
			
转:http://blog.csdn.net/coding_me/article/details/39524137 SASL 的认证方式包括: 1. PLAIN:plain是最简单的机制,但 ...
 - (转)JMS简明学习教程
			
转:http://www.cnblogs.com/jjj250/archive/2012/08/08/2628552.html 基础篇 JMS是应用系统或组件之间相互通信的应用程序接口,利用它,我们可 ...
 - Go语言基础:make,new, len, cap, append, delete方法
			
前面提到不少Go的内建函数,这篇文章学习下如何使用.. make 先拿 make 开刀,可是一开始我就进入了误区,因为我想先找到他的源码,先是发现 src/builtin/builtin.go 中 ...
 - 【HDUOJ】4280 Island Transport
			
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4280 题意:有n个岛屿,m条无向路,每个路给出最大允许的客流量,求从最西的那个岛屿最多能运用多少乘客到 ...