Luogu 3302 [SDOI2013]森林
BZOJ 3123
丑陋的常数,BZOJ 19968ms 卡过。
感觉几个思想都挺经典但是挺套路的。
先考虑不连边的情况怎么做,区间第$k$小,想到主席树,每一个结点维护它到根的前缀和,这样子每一次查询$x$到$y$链上的点就相当于主席树上$sum(x) + sum(y) - sum(lca(x, y)) - sum(fa(lca(x, y)))$,时间复杂度一个$log$。
然后想一想连边怎么做,因为我们要维护一个森林的形态,如果暴力连边的话,相当于把$y$作为根建树连到$x$上,我们有一个优化暴力的办法就是每一次都把$siz$小的那一个点建树连到另一个点。
然后发现这样的复杂度就已经对了,证明方法和树剖类似,相当于每一次合并$siz$都会至少扩大一倍,所以对于一个大小为$n$的集合,至多会合并$logn$次,总复杂度$O(nlogn)$,这东西有一个名字叫做启发式合并。
时间复杂度$O(nlog^{2}n)$。
还有一个算是坑点的东西:
(我也是)
虽然感觉题目说得很清楚了,但是我还是没有看
Code:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int N = ;
const int Lg = ;
const int M = 4e7 + ;
const int inf = << ; int testCase, n, m, qn, tot, head[N];
int ans, maxn, ufs[N], siz[N];
int fa[N][Lg], dep[N], a[N], v[N];
bool vis[N]; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} struct Innum {
int val, id;
} in[N]; bool cmp(const Innum &x, const Innum &y) {
if(x.val != y.val) return x.val < y.val;
else return x.id < y.id;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} inline void discrete() {
sort(in + , in + + n, cmp);
in[].val = -inf; for(int cnt = , i = ; i <= n; i++) {
if(in[i].val != in[i - ].val) chkMax(maxn, ++cnt);
a[in[i].id] = cnt;
v[cnt] = in[i].val;
}
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void init() {
for(int i = ; i <= n; i++)
ufs[i] = i, siz[i] = ;
} int find(int x) {
return ufs[x] == x ? x : ufs[x] = find(ufs[x]);
} namespace PSegT {
struct Node {
int lc, rc, sum;
} s[M];
int root[N], nodeCnt; #define mid ((l + r) >> 1) inline void up(int p) {
if(!p) return;
s[p].sum = s[s[p].lc].sum + s[s[p].rc].sum;
} void ins(int &p, int l, int r, int x, int pre) {
s[p = ++nodeCnt] = s[pre], s[p].sum++;
if(l == r) return; if(x <= mid) ins(s[p].lc, l, mid, x, s[pre].lc);
else ins(s[p].rc, mid + , r, x, s[pre].rc); up(p);
} int query(int x, int y, int z, int w, int l, int r, int k) {
if(l == r) return l; int now = s[s[x].lc].sum + s[s[y].lc].sum - s[s[z].lc].sum - s[s[w].lc].sum; if(k <= now) return query(s[x].lc, s[y].lc, s[z].lc, s[w].lc, l, mid, k);
else return query(s[x].rc, s[y].rc, s[z].rc, s[w].rc, mid + , r, k - now);
} } using namespace PSegT; void dfs1(int x, int fat) {
vis[x] = , dep[x] = dep[fat] + , fa[x][] = fat;
for(int i = ; i <= ; i++)
fa[x][i] = fa[fa[x][i - ]][i - ];
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs1(y, x);
}
} inline void swap(int &x, int &y) {
int t = x; x = y; y = t;
} inline int getLca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = ; i >= ; i--)
if(dep[fa[x][i]] >= dep[y])
x = fa[x][i];
if(x == y) return x;
for(int i = ; i >= ; i--)
if(fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][];
} void dfs2(int x) {
root[x] = , ins(root[x], , maxn, a[x], root[fa[x][]]);
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x][]) continue;
dfs2(y);
}
} inline void solve() {
int x, y, k;
read(x), read(y), read(k);
x ^= ans, y ^= ans, k ^= ans;
int z = getLca(x, y), w = fa[z][];
int res = query(root[x], root[y], root[z], root[w], , maxn, k);
printf("%d\n", ans = v[res]);
} int main() {
read(testCase);
for(testCase = ; testCase--; ) {
read(n), read(m), read(qn); memset(head, , sizeof(head)); tot = maxn = ;
init(); for(int i = ; i <= n; i++) {
read(a[i]);
in[i] = (Innum) {a[i], i};
}
discrete(); for(int x, y, i = ; i <= m; i++) {
read(x), read(y);
add(x, y), add(y, x); int fx = find(x), fy = find(y);
if(fx != fy) {
ufs[fx] = fy;
siz[fy] += siz[fx];
}
} memset(vis, , sizeof(vis));
memset(root, , sizeof(root)); nodeCnt = ;
for(int i = ; i <= n; i++) {
if(vis[i]) continue;
dfs1(find(i), ), dfs2(find(i));
} ans = ;
for(char op[]; qn--; ) {
scanf("%s", op);
if(op[] == 'Q') solve();
else {
int x, y;
read(x), read(y);
x ^= ans, y ^= ans; int fx = find(x), fy = find(y);
if(siz[fx] > siz[fy]) swap(fx, fy); add(x, y), add(y, x);
dfs1(y, x), dfs2(y); ufs[fy] = fx, siz[fx] += siz[fy];
}
} }
return ;
}
Luogu 3302 [SDOI2013]森林的更多相关文章
- BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]
3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...
- luoguP3302 [SDOI2013]森林 主席树 启发式合并
题目链接 luoguP3302 [SDOI2013]森林 题解 本来这题树上主席树暴力启发式合并就完了 结果把lca写错了... 以后再也不这么写了 复杂度\(O(nlog^2n)\) "f ...
- P3302 [SDOI2013]森林(主席树+启发式合并)
P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...
- [BZOJ3123][Sdoi2013]森林 主席树+启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当 ...
- BZOJ3123: [Sdoi2013]森林(启发式合并&主席树)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4813 Solved: 1420[Submit][Status ...
- 【BZOJ3123】[Sdoi2013]森林 主席树+倍增LCA+启发式合并
[BZOJ3123][Sdoi2013]森林 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整 ...
- luogu P3305 [SDOI2013]费用流
题目链接 bz似乎挂了... luogu P3305 [SDOI2013]费用流 题解 dalao告诉我,这题 似乎很水.... 懂了题目大意就可以随便切了 问1,最大流 问2,二分最大边权求,che ...
- 洛谷 P3302 [SDOI2013]森林 解题报告
P3302 [SDOI2013]森林 题目描述 小\(Z\)有一片森林,含有\(N\)个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有\(M\)条边. 小Z希望执行\(T\)个操作,操 ...
- 3123: [Sdoi2013]森林
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 3336 Solved: 978[Submit][Status] ...
随机推荐
- javascript.history.go();
转自:http://www.mikebai.com/Article/2009-11/757.html <input type=button value=刷新 onclick="wind ...
- wordpress 插件 汉化
http://blog.wpjam.com/article/localizing-a-wordpress-plugin-using-poedit/ 翻译或者说本地化 WordPress 插件和主题可以 ...
- Java中print()、printf()、println()的区别?
区别: 1.printf主要是继承了C语言的printf的一些特性,可以进行格式化输出 2.print就是一般的标准输出,输入信息后不会换行 3.println输入信息会换行 参照JAVA API的定 ...
- NAT路由器打洞原理
什么是打洞,为什么要打洞 由于Internet的快速发展 IPV4地址不够用,不能每个主机分到一个公网IP 所以使用NAT地址转换. 下面是我在网上找到的一副图 一般来说都是由私网内主机(例如上图中“ ...
- DCOS安装
安装pre-flight master机器会安装上安装文件(同时check条件是否满足要求),其他的agent设备只是check各种条件是否具备. 确保53/2181端口没有被占用:centos7每次 ...
- bzoj 2982 combination——lucas模板
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2982 明明是lucas定理裸题…… 非常需要注意C( )里 if ( n<m ) r ...
- Python 修改ha配置文件
任务要求: 1.用户输入字符串 {"backend": "test.oldboy.org","record":{"server&q ...
- Python collections系列之默认字典
默认字典(defaultdict) defaultdict是对字典的类型的补充,它默认给字典的值设置了一个类型. 1.创建默认字典 import collections dic = collecti ...
- Poj 3287 Catch That Cow(BFS)
Description Farmer John has been informed of the location of a fugitive cow and wants to catch her i ...
- 基于TCP协议 I/O多路转接(select) 的高性能回显服务器客户端模型
服务端代码: myselect.c #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> ...