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]森林的更多相关文章

  1. BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]

    3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...

  2. luoguP3302 [SDOI2013]森林 主席树 启发式合并

    题目链接 luoguP3302 [SDOI2013]森林 题解 本来这题树上主席树暴力启发式合并就完了 结果把lca写错了... 以后再也不这么写了 复杂度\(O(nlog^2n)\) "f ...

  3. P3302 [SDOI2013]森林(主席树+启发式合并)

    P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...

  4. [BZOJ3123][Sdoi2013]森林 主席树+启发式合并

    3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当 ...

  5. BZOJ3123: [Sdoi2013]森林(启发式合并&主席树)

    3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4813  Solved: 1420[Submit][Status ...

  6. 【BZOJ3123】[Sdoi2013]森林 主席树+倍增LCA+启发式合并

    [BZOJ3123][Sdoi2013]森林 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整 ...

  7. luogu P3305 [SDOI2013]费用流

    题目链接 bz似乎挂了... luogu P3305 [SDOI2013]费用流 题解 dalao告诉我,这题 似乎很水.... 懂了题目大意就可以随便切了 问1,最大流 问2,二分最大边权求,che ...

  8. 洛谷 P3302 [SDOI2013]森林 解题报告

    P3302 [SDOI2013]森林 题目描述 小\(Z\)有一片森林,含有\(N\)个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有\(M\)条边. 小Z希望执行\(T\)个操作,操 ...

  9. 3123: [Sdoi2013]森林

    3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3336  Solved: 978[Submit][Status] ...

随机推荐

  1. HDU3577Fast Arrangement(线段树+lazy)

    Problem Description Chinese always have the railway tickets problem because of its' huge amount of p ...

  2. LeetCode Shopping Offers

    原题链接在这里:https://leetcode.com/problems/shopping-offers/description/ 题目: In LeetCode Store, there are ...

  3. 【JVM】java的内存泄露问题

    一.GC可回收的对象 二:什么是内存泄露--->Java的一个最显著的优势是内存管理.你只需要简单的创建对象而不需要负责释放空间,因为Java的垃圾回收器会负责内存的回收.然而,情况并不是这样简 ...

  4. 【javascript常见面试题】常见前端面试题及答案

    转自:http://www.cnblogs.com/syfwhu/p/4434132.html 前言 本文是在GitHub上看到一个大牛总结的前端常见面试题,很多问题问的都很好,很经典.很有代表性.上 ...

  5. 对django rest_framework的个人理解

    首先要搞清楚web service 和rest都是一种API设计的架构,简单点说 作为一个api开发者,为了保证跨语言.跨平台的高效api,我们可以采用架构师提出的设计架构的理念去设计符合条件的api ...

  6. EJB到底是什么,真的那么神秘吗?? (转)

    1. 我们不禁要问,什么是"服务集群"?什么是"企业级开发"? 既然说了EJB 是为了"服务集群"和"企业级开发",那么 ...

  7. bzoj 4403 序列统计——转化成组合数的思路

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4403 先说说自己的想法吧. 设f[ i ][ j ]表示当前在倒数第 i 个位置,当前和后面 ...

  8. 机器学习:SVM(核函数、高斯核函数RBF)

    一.核函数(Kernel Function) 1)格式 K(x, y):表示样本 x 和 y,添加多项式特征得到新的样本 x'.y',K(x, y) 就是返回新的样本经过计算得到的值: 在 SVM 类 ...

  9. spring事务 异常回滚

    spring事务回滚 可抛出自定义继承自RuntimeException

  10. mysql查询最近30天、7天、每天、昨天、上个月的记录

      一些变量说明: add_time为插入的时间 to_days是sql函数,返回的是个天数 data_sub(date,INTERVAL expr type)给指定的日期减去多少天 data()函数 ...