zoukankan      html  css  js  c++  java
  • [UOJ#274][清华集训2016]温暖会指引我们前行

    [UOJ#274][清华集训2016]温暖会指引我们前行

    试题描述

    寒冬又一次肆虐了北国大地

    无情的北风穿透了人们御寒的衣物

    可怜虫们在冬夜中发出无助的哀嚎

    “冻死宝宝了!”

    这时

    远处的天边出现了一位火焰之神

    “我将赐予你们温暖和希望!”

    只见他的身体中喷射出火焰之力

    通过坚固的钢铁,传遍了千家万户

    这时,只听见人们欢呼

    “暖气来啦!”

    任务描述

    虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低。

    小R的宿舍楼中有n个地点和一些路,一条路连接了两个地点,小R可以通过这条路从其中任意一个地点到达另外一个地点。但在刚开始,小R还不熟悉宿舍楼中的任何一条路,所以他会慢慢地发现这些路,他在发现一条路时还会知道这条路的温度和长度。每条路的温度都是互不相同的。

    小R需要在宿舍楼中活动,每次他都需要从一个地点到达另一个地点。小R希望每次活动时经过一条最温暖的路径,最温暖的路径的定义为,将路径上各条路的温度从小到大排序后字典序最大。即温度最低的路温度尽量高,在满足该条件的情况下,温度第二低的路温度尽量高,以此类推。小R不会经过重复的路。由于每条路的温度互不相同,因此只存在一条最温暖的路径。

    对于小R的每次活动,你需要求出小R需要走过的路径总长度。如果小R通过当前发现的路不能完成这次活动,则输出 1

    注意本题中的字典序与传统意义上的字典序定义有所不同,对于两个序列a,b(ab),若ab的前缀则a的字典序较大,同时可以推出空串的字典序最大。

    输入

    第一行两个正整数 n,m。表示小R的宿舍楼中有 n 个地点,共发生了 m 个事件。

    接下来 m 行,每行描述一个事件,事件分为三类。

    1. find id u v t l 表示小R发现了一条连接uv之间的路,编号为id。相同id的边只会出现一次。

    2. move u v 表示小R要从u到达v,你需要计算出最温暖的路径的长度 ,若不能从u到达v,则输出1

    3. change id l 表示从uv这条边的长度变为了l(保证在当前时间点这条边存在)。

    输出

    对于每个询问,输出一行整数,表示最温暖的路径长度。

    输入示例

    8 19
    find 0 0 2 7 2
    find 1 2 4 4 4
    find 2 4 6 10 1
    find 3 6 7 8 6
    move 2 7
    move 1 6
    find 4 2 5 3 4
    move 0 5
    change 0 12
    find 5 4 5 5 10
    find 6 2 3 6 9
    move 3 5
    find 7 0 1 12 1
    move 1 6
    find 8 1 7 11 100
    move 1 6
    move 3 7
    move 5 6
    move 2 2

    输出示例

    11
    -1
    6
    23
    18
    106
    122
    11
    0

    数据规模及约定

    对于find操作:(0id<m,0u,v<n,uv,0t1000000000,0l10000)

    对于move操作:(0u,v<n)

    对于change操作:(0l10000)

    对于100%的数据,1n100000,1m300000

    题解

    维护最大生成树,裸的 LCT。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define maxq 300010
    #define maxnode 400010
    #define oo 2147483647
    
    struct Node {
    	int t, l, mnid, sum;
    	bool rev;
    	Node(): rev(0) {}
    	Node(int t, int l): t(t), l(l) {}
    } ns[maxnode];
    int fa[maxnode], ch[maxnode][2], S[maxnode], top;
    bool isrt(int u) { return !fa[u] || (ch[fa[u]][0] != u && ch[fa[u]][1] != u); }
    void maintain(int o) {
    	ns[o].mnid = o; ns[o].sum = ns[o].l;
    	for(int i = 0; i < 2; i++) if(ch[o][i]) {
    		int son = ns[ch[o][i]].mnid, &me = ns[o].mnid;
    		if(ns[son].t < ns[me].t) me = son;
    		ns[o].sum += ns[ch[o][i]].sum;
    	}
    	return ;
    }
    void pushdown(int o) {
    	if(!ns[o].rev) return ;
    	swap(ch[o][0], ch[o][1]);
    	for(int i = 0; i < 2; i++) if(ch[o][i])
    		ns[ch[o][i]].rev ^= 1;
    	ns[o].rev = 0;
    	return ;
    }
    void rotate(int u) {
    	int y = fa[u], z = fa[y], l = 0, r = 1;
    	if(!isrt(y)) ch[z][ch[z][1]==y] = u;
    	if(ch[y][1] == u) swap(l, r);
    	fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
    	ch[y][l] = ch[u][r]; ch[u][r] = y;
    	maintain(y); maintain(u);
    	return ;
    }
    void splay(int u) {
    	int t = u; S[top = 1] = t;
    	while(!isrt(t)) S[++top] = fa[t], t = fa[t];
    	while(top) pushdown(S[top--]);
    	while(!isrt(u)) {
    		int y = fa[u], z = fa[y];
    		if(!isrt(y)) {
    			if(ch[y][0] == u ^ ch[z][0] == y) rotate(u);
    			else rotate(y);
    		}
    		rotate(u);
    	}
    	return ;
    }
    void access(int u) {
    	splay(u); ch[u][1] = 0; maintain(u);
    	while(fa[u]) splay(fa[u]), ch[fa[u]][1] = u, maintain(fa[u]), splay(u);
    	return ;
    }
    void makeroot(int u) {
    	access(u); ns[u].rev ^= 1;
    	return ;
    }
    void link(int a, int b) {
    	makeroot(b); fa[b] = a;
    	return ;
    }
    void cut(int a, int b) {
    	makeroot(a); access(b); ch[b][0] = fa[a] = 0; maintain(b);
    	return ;
    }
    int _mnid, _sum;
    void query(int a, int b) {
    	makeroot(a); access(b);
    	_mnid = ns[b].mnid; _sum = ns[b].sum;
    	return ;
    }
    
    struct Edge {
    	int u, v;
    	Edge() {}
    	Edge(int _, int __): u(_), v(__) {}
    } es[maxq];
    
    int pa[maxn];
    int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); }
    
    int main() {
    	int n = read(), q = read();
    	for(int i = 1; i <= n; i++) ns[i] = Node(oo, 0), pa[i] = i;
    	char cmd[10];
    	while(q--) {
    		scanf("%s", cmd);
    		if(!strcmp(cmd, "find")) {
    			int id = read() + n + 1, u = read() + 1, v = read() + 1, t = read(), l = read();
    			ns[id] = Node(t, l); es[id-n-1] = Edge(u, v);
    			int U = findset(u), V = findset(v);
    			if(U == V) {
    				query(u, v);
    				if(ns[_mnid].t < t) {
    					cut(es[_mnid-n-1].u, _mnid);
    					cut(_mnid, es[_mnid-n-1].v);
    					link(u, id); link(id, v);
    				}
    			}
    			else {
    				pa[V] = U;
    				link(u, id); link(id, v);
    			}
    		}
    		if(!strcmp(cmd, "move")) {
    			int u = read() + 1, v = read() + 1;
    			if(findset(u) == findset(v)) query(u, v), printf("%d
    ", _sum);
    			else puts("-1");
    		}
    		if(!strcmp(cmd, "change")) {
    			int id = read() + n + 1, l = read();
    			access(id); ns[id].l = l; maintain(id);
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    同一个类生成的对象去重
    关于公众号JavaTokings侵权声明
    消息中间件ActiveMQ使用详解
    重定向和转发的分析与理解
    Oracle SqlPlus导出查询结果
    Sql查询一个列对应多个列
    Jsp标签字典开发_基于Spring+Hibernate
    Oracle数据库导入导出简单备份
    JAVA WEB接口开发简述
    NTKO在线office控件使用实例
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6687344.html
Copyright © 2011-2022 走看看