BZOJ 3123 LCA + 主席树 + 启发式合并
来源:互联网 发布:数据录入兼职平台 编辑:程序博客网 时间:2024/05/23 01:21
大致题意:有两种操作。
1. 查询节点x到节点y的路径上的第k小。
2. 连接点x和点y。
本题只有一组测试样例,且存在垃圾数据!
需要离散化不必多说。
对于第一种操作,经典的LCA + 主席树问题。每次以父亲节点为上一版本建树,对于一次询问的答案就是在区间
对于第二种操作,每次启发式合并即可。对于新加入的点,需要对这些点进行LCA和主席树的相关信息的更新。
总复杂度
#include <bits/stdc++.h>#define all(x) x.begin(), x.end()using namespace std;/*1. 树上路径第k小。转化成LCA+主席树2. 点之间连边,启发式合并3. 点权大,离散化*/const int maxn = 88000;int ans, t, n, m, q;int val[maxn];vector<int> G[maxn];vector<int> V, C;int getid(int x) { return lower_bound(all(V), x) - V.begin() + 1;}int getval(int x) { return V[x-1];}struct seg{ int l, r, sum;} tr[maxn*100];int idc, root[maxn];void update(int &x, int y, int l, int r, int pos, int val) { x = ++idc; tr[x] = tr[y]; tr[x].sum += val; if(l == r) return ; int m = (l + r) >> 1; if(pos <= m) update(tr[x].l, tr[y].l, l, m, pos, val); else update(tr[x].r, tr[y].r, m+1, r, pos, val);}int ask(int x, int f1, int y, int f2, int l, int r, int k) { if(l == r) return l; int m = (l + r) >> 1; int sum = tr[tr[x].l].sum - tr[tr[f1].l].sum + tr[tr[y].l].sum - tr[tr[f2].l].sum; if(sum >= k) return ask(tr[x].l, tr[f1].l, tr[y].l, tr[f2].l, l, m, k); else ask(tr[x].r, tr[f1].r, tr[y].r, tr[f2].r, m+1, r, k-sum);}int p[maxn][20], dep[maxn];void dfs(int u, int fa) { C.push_back(u); dep[u] = dep[fa] + 1; p[u][0] = fa; update(root[u], root[fa], 1, V.size(), getid(val[u]), 1); for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(v == fa) continue; dfs(v, u); }}int lca_up(int u, int len) { for(int i = 0; i < 20; i++) { if(u != 0 && len&(1<<i)) u = p[u][i]; } return u;}int lca(int u, int v) { if(dep[u] < dep[v]) swap(u, v); u = lca_up(u, dep[u] - dep[v]); if(v == u) return v; for(int i = 19; i >= 0; i--) { if(p[u][i] == p[v][i]) continue; u = p[u][i]; v = p[v][i]; } return p[u][0];}void lca_update() { for(int j = 1; j < 20; j++) { for(int _ = 0; _ < C.size(); _++) { int i = C[_]; if(p[i][j-1] == 0) p[i][j] = 0; else p[i][j] = p[p[i][j-1]][j-1]; } } C.clear();}int fa[maxn], sz[maxn];int find(int x) { return x == fa[x]? fa[x] : fa[x] = find(fa[x]);}void unite(int x, int y) { int f1 = find(x), f2 = find(y); if(f1 == f2) return ; sz[f1] += sz[f2]; fa[f2] = f1;}void init() { V.clear(); C.clear(); for(int i = 0; i < maxn; i++) G[i].clear(), fa[i] = i, sz[i] = 1; ans = idc = 0;}int main() { scanf("%d", &t); init(); scanf("%d%d%d", &n, &m, &q); for(int i = 1; i <= n; i++) scanf("%d", &val[i]), V.push_back(val[i]); sort(all(V)); V.erase(unique(all(V)), V.end()); for(int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); unite(u, v); } dep[0] = 0; for(int i = 1; i <= n; i++) if(!dep[i]) dfs(i, 0); lca_update(); while(q--) { char cmd; scanf(" %c", &cmd); if(cmd == 'Q') { int x, y, k; scanf("%d%d%d", &x, &y, &k); x ^= ans, y ^= ans, k ^= ans; int lc = lca(x, y); printf("%d\n", ans = getval(ask(root[x], root[lc], root[y], root[p[lc][0]], 1, V.size(), k))); } else { int x, y; scanf("%d%d", &x, &y); x ^= ans, y ^= ans; int f1 = find(x), f2 = find(y); if(sz[f1] < sz[f2]) swap(x, y); unite(x, y); G[x].push_back(y); G[y].push_back(x); dfs(y, x); lca_update(); } } return 0;}
阅读全文
0 0
- BZOJ 3123 LCA + 主席树 + 启发式合并
- BZOJ 3123 主席树 启发式合并
- BZOJ 3123 森林 主席树启发式合并
- bzoj 3123(主席树+启发式合并)
- 3123: [Sdoi2013]森林 主席树+启发式合并+LCA
- BZOJ 3123 [Sdoi2013]森林 主席树+启发式合并
- BZOJ 3123: [Sdoi2013]森林|主席树|启发式合并
- [主席树 启发式合并] BZOJ 3123 [Sdoi2013]森林
- 【BZOJ 3123】[Sdoi2013]森林 启发式合并主席树
- Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)
- BZOJ 3123: [Sdoi2013]森林 启发式合并 树上主席树
- bzoj 3123: [Sdoi2013]森林 (主席树+启发式合并+并查集)
- BZOJ 3123 SDOI2013 森林 可持久化线段树+倍增LCA+启发式合并
- [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+倍增lca+启发式合并)
- BZOJ 2588 LCA + 主席树
- Bzoj 3673: 可持久化并查集 by zky(主席树+启发式合并)
- bzoj3123 森林 主席树&启发式合并
- 【bzoj3123】【sdoi2013】【森林】【启发式合并+主席树】
- 安卓7.0文件存储权限变更
- mtk 平台 CAMERA 驱动浅析
- 这些人都在使用超级表格
- ListView 侧滑删除
- vue的单向数据流和双向绑定解释
- BZOJ 3123 LCA + 主席树 + 启发式合并
- 【SoapUI】2、SoapUI进行API Mock测试分析
- 字符串排序
- 变量本质分析
- linux 下文件的创建时间、访问时间、修改时间和改变时间
- GLSL 转UnityShader
- mongoDB的入门
- xss攻击方法简单介绍了解
- Android4.4以上Uri转换成绝对路径的工具类