Luogu3302森林

mac2022-06-30  65

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\n",ans); } else { int u = read() ^ ans, v = read() ^ ans; link(u, v, 1); } } return 0; }

转载于:https://www.cnblogs.com/LZYcaiji/p/10397856.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)