• 【BZOJ3551】[ONTAK2010]Peaks加强版


    【BZOJ3551】[ONTAK2010]Peaks加强版

    题面

    给你一个图,每次询问给定一个位置、长度和(k),问从这个点出发,只能经过不大于这个长度的边,到达的点中点权第(k)大的点权

    图的规模:(10^5)

    题解

    考虑离线怎么做:

    将所有询问存下来,按照边权排序

    每次加边线段树合并查(kth)即可

    然鹅:离线加边一时爽,强制在线火葬场。

    我们考虑强制在线怎么做:

    妈妈!!我会(Kruskal)重构树!!!

    我们有(Kruskal)重构树(这里是(MST))的性质:深度越深,节点权值越小

    可以二分一下最浅的权值小于等于(k)的点,那么直接在它子树内用主席树(kth)就行了

    辣鸡bzoj,这题空间开得神他妈玄学,稍微变一点就会挂

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring> 
    #include <cmath> 
    #include <algorithm>
    using namespace std; 
    inline int gi() {
    	register int data = 0, w = 1;
    	register char ch = 0;
    	while (!isdigit(ch) && ch != '-') ch = getchar(); 
    	if (ch == '-') w = -1, ch = getchar();
    	while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
    	return w * data; 
    }
    const int MAX_N = 2e5 + 5;
    const int MAX_LOG_N = 17; 
    struct Node { int ls, rs, v; } t[MAX_N * 25];
    int tot, rt[MAX_N << 1]; 
    void insert(int &o, int p, int l, int r, int pos) { 
    	o = ++tot, t[o] = t[p], ++t[o].v; 
    	if (l == r) return ; 
    	int mid = (l + r) >> 1; 
    	if (pos <= mid) insert(t[o].ls, t[p].ls, l, mid, pos); 
    	else insert(t[o].rs, t[p].rs, mid + 1, r, pos); 
    } 
    int query(int v, int u, int l, int r, int k) { 
    	if (l == r) return l; 
    	int mid = (l + r) >> 1, res = t[t[u].ls].v - t[t[v].ls].v; 
    	if (res >= k) return query(t[v].ls, t[u].ls, l, mid, k); 
    	else return query(t[v].rs, t[u].rs, mid + 1, r, k - res); 
    } 
    struct Graph { int to, next; } e[MAX_N << 1]; int fir[MAX_N], e_cnt;
    void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; } 
    void Add_Edge(int u, int v) { e[e_cnt] = (Graph){v, fir[u]}, fir[u] = e_cnt++; } 
    struct Edge { int u, v, w; } a[MAX_N << 2]; 
    bool operator < (const Edge &l, const Edge &r) { return l.w < r.w; } 
    int N, M, Q, h[MAX_N]; 
    int pa[MAX_N], val[MAX_N]; 
    int getf(int x) { return (x == pa[x]) ? x : (pa[x] = getf(pa[x])); } 
    int fa[MAX_N][MAX_LOG_N], mx[MAX_N][MAX_LOG_N], p[MAX_N << 1], dep[MAX_N], top; 
    int st[MAX_N], ed[MAX_N]; 
    bool vis[MAX_N]; 
    void dfs(int x) {
    	vis[x] = 1, p[++top] = x; 
    	for (int i = 1; i <= 16; i++) 
    		if (dep[x] >= (1 << i)) { 
    		    fa[x][i] = fa[fa[x][i - 1]][i - 1]; 
    	        mx[x][i] = max(mx[x][i - 1], mx[fa[x][i - 1]][i - 1]); 
    		}
    		else break; 
    	
    	for (int i = fir[x]; ~i; i = e[i].next) { 
    		int v = e[i].to; 
    		dep[v] = dep[x] + 1; 
    		mx[v][0] = val[x]; 
    		fa[v][0] = x; 
    		dfs(v); 
    	} 
    	if (x > N) p[++top] = x; 
    } 
    void build() { 
    	int ext = N; 
    	sort(&a[1], &a[M + 1]); 
    	for (int i = 1; i <= 2 * N; i++) pa[i] = i; 
    	for (int i = 1; i <= M; i++) { 
    		int x = getf(a[i].u), y = getf(a[i].v); 
    		if (x != y) { 
    			ext++; 
    			pa[x] = pa[y] = ext; 
    			val[ext] = a[i].w;
    			Add_Edge(ext, y); 
    			Add_Edge(ext, x); 
    			if (ext == 2 * N - 1) break; 
    		} 
    	} 
    	for (int i = 1; i <= N; i++) if (!vis[i]) dfs(getf(i)); 
    	for (int i = 1; i <= top; i++) { 
    		int x = p[i];
    		if (x <= N) insert(rt[i], rt[i - 1], 1, N, h[x]); 
    		else {
    			rt[i] = rt[i - 1]; 
    			if (st[x] == 0) st[x] = i;
    			else ed[x] = i; 
    		} 
    	} 
    } 
    int find(int x, int v) { 
    	for (int i = 17; i >= 0; i--) 
    		if (dep[x] >= (1 << i) && mx[x][i] <= v) x = fa[x][i]; 
    	return x; 
    }
    int X[MAX_N]; 
    int main () { 
    	clearGraph(); 
    	N = gi(), M = gi(), Q = gi();
    	for (int i = 1; i <= N; i++) X[i] = h[i] = gi(); 
    	for (int i = 1; i <= M; i++) {
    		int u = gi(), v = gi(), w = gi(); 
    		a[i] = (Edge){u, v, w}; 
    	} 
    	sort(&X[1], &X[N + 1]); 
    	for (int i = 1; i <= N; i++) h[i] = lower_bound(&X[1], &X[N + 1], h[i]) - X; 
    	build(); int ans = 0; 
    	while (Q--) {
    		int v = gi(), x = gi(), k = gi();
    		if (ans != -1) v ^= ans, x ^= ans, k ^= ans; 
    		x = find(v, x); 
    		int l = st[x], r = ed[x]; 
    		if (t[rt[r]].v - t[rt[l - 1]].v < k) ans = -1; 
    		else ans = X[query(rt[l], rt[r], 1, N, t[rt[r]].v - t[rt[l - 1]].v - k + 1)]; 
    		printf("%d
    ", ans); 
    	} 
    	return 0; 
    } 
    
  • 相关阅读:
    Picture
    wolf and rabbit
    十进制转换为二进制(一直不会算的)
    各种排序
    折线分割平面
    字母数
    1001
    Primes
    大数的减法神秘数
    转: Windows Internet WinINet 学习笔记(2)
  • 原文地址:https://www.cnblogs.com/heyujun/p/10334460.html
Copyright © 2020-2023  润新知