• 空间宝石「最短路+线段树」


    空间宝石「最短路+线段树」

    题目描述

    zP1nG很清楚自己打不过灭霸,所以只能在自己出的题里欺负他。

    咳咳。这一次他得到了空间宝石Tesseract。

    世界之树连接着九界,此时灭霸和zP1nG都在九界的某个地方。而九界是相互无法到达的。zP1nG为了追杀灭霸,决定使用空间宝石的力量到达灭霸身边。因为zP1nG不擅长使用空间宝石,无法直接开一条从自己的位置到灭霸的位置的传送门,所以他只能无意识地使用空间宝石的力量。zP1nG想知道,在自己胡乱地使用空间宝石后,通过传送门到达灭霸的位置最少需要多长时间。

    具体地,九界的编号为 (0)~(8),共有 (n) 道传送门,第 (i) 道传送门为优先级为 (p_i),由 (u_i)(v_i),需要花费 (w_i) 个时间的单向门。传送的规则为:zP1nG按顺序穿过的传送门的优先级必须是单调不降的。例如,zP1nG穿过了三道传送门到达灭霸的位置,这三道传送门的优先级分别为 (1→2→2) 即为一种合法的方式,而优先级分别为 (1→2→1) 是不合法的。

    zP1nG会使用 (q) 次宝石的力量来尝试进行传送:其中第 (i) 次尝试会打开数道传送门,这些传送门的优先级会形成 (s_i) 个区间。例如,在某次尝试中zP1nG打开了三个区间 ([1,2],[4,7],[9,10]),那么优先级在这三个区间内的传送门将全部被打开并允许zP1nG穿过。你需要告诉zP1nG在此情况下从自己的位置 (z_i) 到达灭霸所在处 (t_i) 所需的最短时间。尝试结束后所有传送门会关闭。

    输入格式

    (1) 行包含两个正整数 (n)(S)(S)的含义见数据范围与约定所述。

    (2)(n+1) 行每行包含 (4) 个正整数 (p_i,u_i,v_i,w_i)

    (n+2) 行包含一个正整数 (q)

    (n+3) 至第 (n+q+2) 行每行若干个正整数,其中前三个数为 (z_i,t_i,s_i),之后为(2*s_i) 个正整数,表示每个区间的左右端点。

    各变量具体含义见题目描述所述。

    输出格式

    对于zP1nG进行的每次尝试,输出一行一个数表示从zP1nG的位置到灭霸的位置所需的最短时间,如果zP1nG无法到达灭霸的位置则输出 (-1)

    样例

    样例输入

    6 2
    1 2 4 1
    2 1 3 3
    3 1 2 2
    4 3 4 5
    5 2 4 3
    6 1 4 2
    4
    1 4 1 1 3
    1 4 1 1 4
    1 4 2 5 5 2 3
    1 4 1 1 6
    

    样例输出

    -1
    8
    5
    2
    

    数据范围与提示

    对于100%的数据,(1≤n≤100,000,1≤S≤5,1≤pi≤2,000,ui≠vi,zi≠ti,1≤wi≤100,000,000,1≤∑si≤10,000)

    思路分析

    这题够毒瘤的

    • 首先第一眼看上去应该是让我们求一个带有奇奇怪怪限制的最短路,再进一步看,发现这题只有9个节点???暴力蠢蠢欲动然后上去糊了一个二维spfa完美死掉,我太菜了
    • 只有九个节点,这时侯肯定是邻接矩阵存边最方便了,而相应的 (Floyd) 也就呼之欲出。不同优先级的边可以存在不同的矩阵里
    • 那么关键问题来了,不同优先级要怎么合并在一起?其实只要将两个矩阵一起再跑一遍 (Floyd) 就可以,联想到矩阵乘,稍微改成 (Floyd) 的形式就行了(因为这两个形式差不多)
    • 到这里还并不是最优解,由于我们每次打开的传送门是一个区间,这当然是线段树最擅长的,通过线段树合并即可

    详见代码

    (Code)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #define N 2020
    #define R register
    using namespace std;
    inline int read(){
    	int x=0,f=1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    const int inf = 0x3f3f3f3f;
    int n,S,q,Max = -1;
    struct Martix{ //邻接矩阵来存不同优先级
    	int a[10][10];
    	Martix(){ //初始化
    		memset(a,0x3f,sizeof(a));
    		for(int i = 0;i < 9;i++)a[i][i] = 0;
    	}
    	Martix operator*(const Martix &r)const{ //魔改一下矩阵乘
    		Martix res;
    		for(int k = 0;k < 9;k++){
    			for(int i = 0;i < 9;i++){
    				for(int j = 0;j < 9;j++)
    					res.a[i][j] = min(res.a[i][j],a[i][k]+r.a[k][j]);
    			}
    		}
    		return res;
    	}
    }a[N],tr[N<<2];
    #define ls u<<1
    #define rs u<<1|1
    void build(int u,int l,int r){ //线段树进行合并
    	if(l==r){tr[u] = a[l];return;}
    	int mid = (l+r)>>1;
    	build(ls,l,mid);
    	build(rs,mid+1,r);
    	tr[u] = tr[ls]*tr[rs]; //注意是左右儿子放在一起跑一遍Floyd
    }
    Martix query(int u,int l,int r,int s,int t){
    	if(s<=l&&t>=r)return tr[u];
    	int mid = (l+r)>>1;
    	if(t<=mid)return query(ls,l,mid,s,t);
    	if(s>mid)return query(rs,mid+1,r,s,t);
    	return query(ls,l,mid,s,t)*query(rs,mid+1,r,s,t);
    }
    struct node{ //结构体放在优先队列里用,根据优先级,即左端点小的优先
    	int l, r;
    	node(){}
    	node(int _l,int _r){
    		l = _l,r = _r;
    	}
    	bool operator <(const node &a)const{
    		return l > a.l;
    	}
    };
    int main(){
    	n = read(),S = read();
    	for(int i = 1;i <= n;i++){
    		int p,u,v,w;
    		p = read(),u = read(),v = read(),w = read();
    		if(a[p].a[u][v]>=w)a[p].a[u][v] = w;//处理重边
    		Max = max(Max,p); //处理出线段树的右端点
    	}
    	for(int th  = 1;th <= Max;th++){ //两个矩阵放一起之前先求出同一矩阵的最短路
    		for(int k = 0;k < 9;k++){
    			for(int i = 0;i < 9;i++){
    				for(int j = 0;j < 9;j++){
    					a[th].a[i][j] = min(a[th].a[i][j],a[th].a[i][k]+a[th].a[k][j]);
    				}
    			}
    		}
    	}
    	build(1,1,Max);
    	q = read();
    	for(int i = 1;i <= q;i++){
    		int z,t,s;z = read(),t = read(),s = read();
    		priority_queue<node>q;
    		for(int j = 1;j <= s;j++){
    			int l,r;l = read(),r = read();
    			q.push(node(l,r));
    		}
    		Martix ans;
    		for(int j = 1;j <= s;j++){
    			node p = q.top();q.pop();
    			int l = p.l,r = p.r;
    			ans = ans*query(1,1,Max,l,r); //每次询问乘上就好
    		}
    		if(ans.a[z][t]<inf)printf("%d
    ",ans.a[z][t]);
    		else puts("-1");
    	}
    	return 0;
    }
    
  • 相关阅读:
    POJ2993——Emag eht htiw Em Pleh(字符串处理+排序)
    POJ2109——Power of Cryptography
    POJ2993——Help Me with the Game(字符串处理+排序)
    POJ1573——Robot Motion
    POJ2632——Crashing Robots
    POJ1068——Parencodings
    POJ3295——Tautology
    POJ2506——Tiling
    POJ2524——Ubiquitous Religions
    性能问题“三板斧”
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13437487.html
Copyright © 2020-2023  润新知