zoukankan      html  css  js  c++  java
  • [OJ#40]后宫佳丽

    [OJ#40]后宫佳丽

    试题描述

    如果机房要关门了,或者有妹子在等你,你可以直接看最后一句话。

    Fyq 是一只饥渴的鸭子。

    Fyq 有一个充实的后宫,可惜他总是体力不支,为此他经常苦恼,总是想方设法让自己能够泡到更多妃子。

    Fyq 为他的的每个妃子建立了一间屋子,屋子与屋子之间可能有一条路连接。每条路有一个长度 len,Fyq 走过这条路时会消耗 len 的体力,但是当 Fyq 进入一间屋子云雨一翻后,体力立刻恢复至初始值。每个妃子有一个类型 typei,Fyq 希望知道他见到次数最多的会是哪个类型,以便做更加充分的准♂备。注意,如果有见到次数并列第一的几个类型,那么请输出类型编号最小的,因为 Fyq 更加偏爱类型编号小的妃子。

    接下来有 q 天,Fyq 每天都打算找他的妃子们。第 i 天他会从妃子 xi 的屋子出发,初始时有 wi 的体力。你不能让 Fyq 太虚导致他无法好好享受,所以你要保证任何时刻不能让他的体力值低于 0

    一句话题意:给你一个 n 个节点 m 条边的无向图,边有长度,点带颜色(节点 i 的颜色为 typei);给你 q 个询问形如 (xi,wi),每次你从节点 xi 出发,只能走长度不超过 wi 的边,问经过的所有节点中颜色数目最多的颜色是哪个(如果有多个并列,输出颜色编号最小的)。

    (无向图有可能不连通。)

    输入

    第一行三个整数 n,m,secretsecret 的含义待会解释。

    第二行 n 个整数,第 i 个整数表示 typei

    接下来 m 行每行三个整数 u,v,len,表示 uv 之间有一条长度为 len 的双向边。

    接下来一行一个整数 q

    接下来 q 行,每行两个整数 xi,wi 表示 Fyq 一天的计划。

    secret 的值域为 {0,1},若 secret=1 表示 Fyq 比较害羞,他不肯一次告诉你接下来 q 天的所有计划,所以他对计划进行了加密,解密的方式 xi 和 wi 都异或上 lastanslastans 表示昨天的答案;如果是第一天 lastans=0,即第一天的信息 Fyq 没有加密。

    输出

    输出 q 行,第 i 行一个整数表示第 i 天的答案。

    输入示例1

    5 6 0
    2 1 1 3 2
    1 2 2
    1 3 4
    2 3 7
    3 4 5
    4 5 6
    5 3 3
    4
    1 1
    2 2
    4 4
    5 8

    输出示例1

    2
    1
    3
    1

    输入示例2

    5 6 1
    2 1 1 3 2
    1 2 2
    1 3 4
    2 3 7
    3 4 5
    4 5 6
    5 3 3
    4
    1 1
    0 0
    5 5
    6 11

    输出示例2

    2
    1
    3
    1

    数据规模及约定

    对于 20% 的数据,1n1000

    对于另外 40% 的数据,secret=0

    对于全部数据,1n1051m,q2×1051typei,u,v,xin1len,wi106

    题解

    我们构出 kruskal 重构树,问题变成了求子树内最小众数,可以自底向上用平衡树启发式合并算出每个节点的子树的答案。

    关于 kruskal 重构树可以去看一下这道题

    #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 maxm 200010
    #define maxlog 18
    
    struct Node {
    	int col, val, r, siz;
    	Node() {}
    	Node(int _1, int _2, int _3): col(_1), val(_2), r(_3) {}
    	bool operator < (const Node& t) const { return val != t.val ? val < t.val : col > t.col; }
    } ns[maxn];
    int ToT, ch[maxn][2], fa[maxn], rec[maxn], rcnt;
    int getnode() {
    	if(rcnt) {
    		int o = rec[rcnt--];
    		ch[o][0] = ch[o][1] = fa[o] = 0;
    		return o;
    	}
    	return ++ToT;
    }
    void maintain(int o) {
    	if(!o) return ;
    	ns[o].siz = ns[ch[o][0]].siz + 1 + ns[ch[o][1]].siz;
    	return ;
    }
    void rotate(int u) {
    	int y = fa[u], z = fa[y], l = 0, r = 1;
    	if(z) 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 ;
    }
    Node opt;
    void Add(int& o, int col, int val) {
    	if(!o) {
    		ns[o = getnode()] = Node(col, val, rand()); opt = max(opt, ns[o]);
    		return maintain(o);
    	}
    	if(ns[o].col == col){ ns[o].val += val; opt = max(opt, ns[o]); return ; }
    	bool d = col > ns[o].col; opt = max(opt, ns[o]);
    	Add(ch[o][d], col, val); fa[ch[o][d]] = o;
    	if(ns[ch[o][d]].r > ns[o].r) {
    		int t = ch[o][d];
    		rotate(t); o = t;
    	}
    	return maintain(o);
    }
    Node Set[maxn]; int cnts;
    void recycle(int& o) {
    	if(!o) return ;
    	Set[++cnts] = ns[o];
    	rec[++rcnt] = o;
    	recycle(ch[o][0]); recycle(ch[o][1]);
    	o = 0;
    	return ;
    }
    
    struct Edge {
    	int a, b, c;
    	Edge() {}
    	Edge(int _1, int _2, int _3): a(_1), b(_2), c(_3) {}
    	bool operator < (const Edge& t) const { return c < t.c; }
    } es[maxm];
    
    int pa[maxn<<1], Rt[maxn<<1];
    int findset(int x){ return x == pa[x] ? x : pa[x] = findset(pa[x]); }
    
    int E, head[maxn<<1], nxt[maxn<<1], to[maxn<<1], Fa[maxn<<1][maxlog];
    void AddEdge(int a, int b) {
    	to[++E] = b; nxt[E] = head[a]; head[a] = E;
    	return ;
    }
    bool vis[maxn<<1];
    void build(int u) {
    	vis[u] = 1;
    	for(int i = 1; i < maxlog; i++) Fa[u][i] = Fa[Fa[u][i-1]][i-1];
    	for(int e = head[u]; e; e = nxt[e])
    		Fa[to[e]][0] = u, build(to[e]);
    	return ;
    }
    
    int color[maxn<<1], totc[maxn<<1], wei[maxn<<1];
    int jump(int u, int W) {
    	for(int i = maxlog - 1; i >= 0; i--) if(Fa[u][i] && wei[Fa[u][i]] <= W) u = Fa[u][i];
    	return u;
    }
    
    int main() {
    	int n = read(), m = read(), online = read();
    	for(int i = 1; i <= n; i++) color[i] = read();
    	for(int i = 1; i <= m; i++) {
    		int a = read(), b = read(), c = read();
    		es[i] = Edge(a, b, c);
    	}
    	
    	sort(es + 1, es + m + 1);
    	for(int i = 1; i < (n << 1); i++) {
    		pa[i] = i;
    		if(i <= n) Add(Rt[i], color[i], 1), totc[i] = 1, wei[i] = 0;
    	}
    	for(int i = 1; i <= m; i++) {
    		int a = findset(es[i].a), b = findset(es[i].b), c;
    		if(a != b) {
    			wei[c = ++n] = es[i].c;
    			if(ns[Rt[a]].siz < ns[Rt[b]].siz) swap(a, b);
    			Rt[c] = Rt[a]; recycle(Rt[b]);
    			opt = Node(color[a], totc[a], 0);
    			while(cnts) Add(Rt[c], Set[cnts].col, Set[cnts].val), cnts--;
    			color[c] = opt.col; totc[c] = opt.val;
    			AddEdge(c, a); AddEdge(c, b);
    			pa[a] = pa[b] = c;
    		}
    	}
    	for(int i = n; i; i--) if(!vis[i]) build(i);
    //	for(int i = 1; i <= n; i++) printf("%d%c", color[i], i < n ? ' ' : '
    ');
    	
    	int q = read(), lst = 0;
    	for(int k = 1; k <= q; k++) {
    		int x = read() ^ lst * online, w = read() ^ lst * online;
    		printf("%d
    ", lst = color[jump(x,w)]);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    day01-python基础
    python3.5爬虫实例:根据网站的反爬虫策略,启用代理来防止爬虫被禁用
    python3.5爬虫实例:根据城市名称来获取该城市最近七天的天气预报
    python3.5爬虫基础urllib结合beautifulsoup实例
    python3.5爬虫基础urllib实例
    面向对象相关知识及常用操作(二)
    面向对象相关知识点及常见的操作
    常用的基础模块介绍
    利用正则表达式来实现求一个数学表达式的和
    正则表达式的方法及其匹配规则
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6606038.html
Copyright © 2011-2022 走看看