• Luogu3302森林


    Problem

    题目传送门

    给你一片森林。

    支持两个操作。

    1,查询x,y路径中点权的k小。

    2,连接x,y.保证连接之后仍然是一片森林。

    询问强制在线。

    (n,m,t<8×10^4)

    solution

    链上第k小参考以前的博客:戳我

    现在只要考虑如何连接两个点。

    难道要用LCT?

    对不起,本caiji还没有学会这么高级的数据结构。

    观察没有删除操作。

    然后:启发式合并。

    每次合并,选择较小的树,遍历一遍,重新继承主席树信息就可以了。

    注意,空间开大一点。

    xunzhen看题1分钟的结论,我想了一个小时都想不出。

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define mp make_pair
    #define fst first
    #define snd second
    
    template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
    template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
    
    inline int read(){
    	int res = 0, fl = 1;
    	char r = getchar();
    	for (; !isdigit(r); r = getchar()) if(r == '-') fl = -1;
    	for (; isdigit(r); r = getchar()) res = (res << 3) + (res << 1) + r - 48;
    	return res * fl;
    }
    typedef long long LL;
    typedef pair<int, int> pii;
    const int Maxn = 8e4 + 10;
    struct SGT{
    	int ls,rs,sum;
    }tre[Maxn << 9];
    int val[Maxn], fa[Maxn][17], cnt, dep[Maxn];
    int num, root[Maxn << 9], B[Maxn], f[Maxn], siz[Maxn];
    vector <int> g[Maxn];
    int LCA(int u,int v){
    	if(dep[u] < dep[v]) swap(u, v);
    	for (int i = 16; i >= 0 ; --i) if(dep[fa[u][i]] >= dep[v]) u = fa[u][i];
    	if(u == v) return u;
    	for (int i = 16; i >= 0 ; --i) if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
    	return fa[u][0];
    }
    void build(int &rt,int grt,int l,int r,int pos){
    	tre[rt = ++cnt] = tre[grt];
    	tre[rt].sum++;
    	if(l == r) return;
    	int mid = l + r >> 1;
    	if(pos <= mid) build(tre[rt].ls, tre[grt].ls, l, mid, pos);
    	else build(tre[rt].rs, tre[grt].rs, mid + 1, r, pos);
    }
    int Query(int a,int b,int c,int d,int l,int r,int k){
    	if(l == r) return B[l];
    	int mid = l + r >> 1, t = tre[tre[a].ls].sum + tre[tre[b].ls].sum - tre[tre[c].ls].sum - tre[tre[d].ls].sum;
    	if(k <= t) return Query(tre[a].ls, tre[b].ls, tre[c].ls, tre[d].ls, l, mid, k);
    	else return Query(tre[a].rs, tre[b].rs, tre[c].rs, tre[d].rs, mid + 1, r, k - t);
    }
    void dfs(int now, int pa){
    	dep[now] = dep[pa] + 1;
    	fa[now][0] = pa;
    	for (int i = 1; i <= 16; ++i) fa[now][i] = fa[fa[now][i - 1]][i - 1];
    	build(root[now],root[pa], 1, num, val[now]);
    	for (int i = g[now].size() - 1; i >= 0; --i){
    		int nxt = g[now][i];
    		if(nxt == pa) continue;
    		dfs(nxt, now);
    	}
    }
    int get_fa(int x){
    	if(f[x] == x) return x;
    	return f[x] = get_fa(f[x]);
    }
    void link(int x, int y,int opt){
    	int fx = get_fa(x), fy = get_fa(y);
    	if (fx == fy) return;
    	if (siz[fx] < siz[fy])
    		swap(fx,fy), swap(x,y);
    	if (opt) {
    		g[x].push_back(y);
    		g[y].push_back(x);
    		dfs(y, x);
    	}
    	f[fy] = fx ,siz[fx] += siz[fy];
    }
    void init(int n, int m){
    	for (int i = 1; i <= n; ++i) B[i] = val[i] = read();
    	sort(B + 1, B + 1 + n);
    	num = unique(B + 1, B + 1 + n) - B - 1;
    	for (int i = 1; i <= n; ++i) val[i] = lower_bound(B + 1, B + num + 1, val[i]) - B;
    	for (int i = 1; i <= n; ++i) f[i] = i, siz[i] = 1;
    	for (int i = 1; i <= m; ++i) {
    		int x = read(), y = read();
    		g[x].push_back(y);
    		g[y].push_back(x);
    		link(x, y, 0);
    	}
    	for (int i = 1; i <= n; ++i) if(!dep[i]) dfs(i, 0);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in", "r", stdin);
    	freopen("a.out", "w", stdout);
    #endif
    	int t = read();
    	int n = read(), m = read(), Q = read();
    	init(n, m);
    	int ans = 0;
    	while (Q--) {
    		char opt = getchar();
    		while(opt != 'Q' && opt != 'L') opt = getchar();
    		if (opt == 'Q') {
    			int u = read() ^ ans, v = read() ^ ans, k = read() ^ ans;
    			int lca = LCA(u,v),flca = fa[lca][0];
    			ans = Query(root[u],root[v],root[lca],root[flca],1,num,k);
    			printf("%d
    ",ans);
    		}
    		else {
    			int u = read() ^ ans, v = read() ^ ans;
    			link(u, v, 1);
    		}
    	}
    	return 0;
    }
    
    
    
  • 相关阅读:
    P1662 数7
    P3645 [APIO2015]雅加达的摩天楼
    P3396 哈希冲突
    P7479 至曾是英雄的您
    P7480 Reboot from Blue
    Apache Commons Collections
    ESP8266 WIFI杀手
    ESP8266 固件升级
    ESP8266 MicroPython安装与使用
    Window 安装子系统
  • 原文地址:https://www.cnblogs.com/LZYcaiji/p/10397856.html
Copyright © 2020-2023  润新知