题目

输入格式

第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。

第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。

接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。

输出格式

对于每一个第一类操作,输出一个非负整数表示答案。

输入样例

1

8 4 8

1 1 2 2 3 3 4 4

4 7

1 8

2 4

2 1

Q 8 7 3 Q 3 5 1

Q 10 0 0

L 5 4

L 3 2 L 0 7

Q 9 2 5 Q 6 1 6

输出样例

2

2

1

4

2

提示

对于第一个操作 Q 8 7 3,此时 lastans=0,所以真实操作为Q 8^0 7^0 3^0,也即Q 8 7 3。点8到点7的路径上一共有5个点,其权值为4 1 1 2 4。这些权值中,第三小的为 2,输出 2,lastans变为2。对于第二个操作 Q 3 5 1 ,此时lastans=2,所以真实操作为Q 3^2 5^2 1^2 ,也即Q 1 7 3。点1到点7的路径上一共有4个点,其权值为 1 1 2 4 。这些权值中,第三小的为2,输出2,lastans变为 2。之后的操作类似。

题解

如果没有连边操作,可以用树上主席树水过

加上了连边操作后,我们考虑暴力重构

每次会连接两个联通块,我们选择其中一个联通块重新dfs构树

选哪一个最合适呢?当然是选择最小的联通块【启发式合并】

可以证明:启发式合并的合并次数最坏情况下是\(O(nlogn)\)

所以总的时间复杂度\(O(nlog^2n)\)

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s) memset(s,0,sizeof(s))
using namespace std;
const int maxn = 80005,maxm = 10000005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
return out * flag;
}
int n,m,T,val[maxn],B[maxn],fa[maxn][18],dep[maxn],tot,lans;
int h[maxn],ne,pre[maxn],num[maxn];
struct EDGE{int to,nxt;}ed[2 * maxn];
int rt[maxn],sum[maxm],ls[maxm],rs[maxm],siz;
int find(int u){return u == pre[u] ? u : pre[u] = find(pre[u]);}
void init(){
tot = 1; ne = 2; lans = siz = 0;
cls(h); cls(rt);
}
void build(int u,int v){
ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v]}; h[v] = ne++;
}
int getn(int x){return lower_bound(B + 1,B + 1 + tot,x) - B;}
void modify(int& u,int pre,int l,int r,int pos,int v){
sum[u = ++siz] = sum[pre] + v; ls[u] = ls[pre]; rs[u] = rs[pre];
if (l == r) return;
int mid = l + r >> 1;
if (mid >= pos) modify(ls[u],ls[pre],l,mid,pos,v);
else modify(rs[u],rs[pre],mid + 1,r,pos,v);
}
int query(int a,int b,int c,int d,int l,int r,int k){
if (l == r) return l;
int mid = l + r >> 1,t = sum[ls[a]] + sum[ls[b]] - sum[ls[c]] - sum[ls[d]];
if (t >= k) return query(ls[a],ls[b],ls[c],ls[d],l,mid,k);
else return query(rs[a],rs[b],rs[c],rs[d],mid + 1,r,k - t);
}
void dfs(int u){
modify(rt[u],rt[fa[u][0]],1,tot,val[u],1);
REP(i,17) fa[u][i] = fa[fa[u][i - 1]][i - 1];
Redge(u) if ((to = ed[k].to) != fa[u][0]){
fa[to][0] = u; dep[to] = dep[u] + 1;
dfs(to);
}
}
int Lca(int u,int v){
if (dep[u] < dep[v]) swap(u,v);
for (int i = 0,d = dep[u] - dep[v]; (1 << i) <= d; i++)
if ((1 << i) & d) u = fa[u][i];
if (u == v) return u;
for (int i = 17; i >= 0; i--)
if (fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];
return fa[u][0];
} void solve(int u,int v,int k){
int lca = Lca(u,v),o = fa[lca][0];
printf("%d\n",lans = B[query(rt[u],rt[v],rt[lca],rt[o],1,tot,k)]);
}
void merge(int u,int v){
build(u,v);
int fu = find(u),fv = find(v);
if (num[fu] < num[fv]) swap(u,v),swap(fu,fv);
pre[fv] = fu; num[fu] += num[fv];
fa[v][0] = u; dep[v] = dep[u] + 1;
dfs(v); }
int main(){
char opt; int u,v,k,fu,fv;
read(); n = read(); m = read(); T = read(); init();
for (int i = 1; i <= n; i++) val[i] = B[i] = read(),pre[i] = i,num[i] = 1;
while (m--){
u = read(); v = read();
build(u,v);
fu = find(u); fv = find(v);
pre[fv] = fu; num[fu] += fv;
}
sort(B + 1,B + 1 + n);
for (int i = 2; i <= n; i++) if (B[i] != B[tot]) B[++tot] = B[i];
for (int i = 1; i <= n; i++) val[i] = getn(val[i]);
for (int i = 1; i <= n; i++) if (!rt[i]){
dep[i] = 1,fa[i][0] = 0; dfs(i);
}
while (T--){
opt = getchar(); while (opt != 'Q' && opt != 'L') opt = getchar();
u = read() ^ lans; v = read() ^ lans;
if (opt == 'Q'){
k = read() ^ lans;
solve(u,v,k);
}else merge(u,v);
}
return 0;
}

BZOJ2123 [Sdoi2013]森林 【主席树 + 启发式合并】的更多相关文章

  1. Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)

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

  2. [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT

    Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...

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

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

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

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

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

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

  6. [SDOI2013]森林 主席树+启发式合并

    这题的想法真的很妙啊. 看到题的第一眼,我先想到树链剖分,并把\(DFS\)序当成一段区间上主席树.但是会发现在询问的时候,可能会非常复杂,因为你需要把路径拆成很多条轻链和重链,它们还不一定连续,很难 ...

  7. 【BZOJ 3123】 [Sdoi2013]森林 主席树启发式合并

    我们直接按父子关系建主席树,然后记录倍增方便以后求LCA,同时用并查集维护根节点,而且还要记录根节点对应的size,用来对其启发式合并,然后每当我们合并的时候我们都要暴力拆小的一部分重复以上部分,总时 ...

  8. 【BZOJ-3123】森林 主席树 + 启发式合并

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

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

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

  10. BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并

    BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20 ...

随机推荐

  1. OO2019第四单元作业总结

    一.本单元两次作业的架构设计  1.第一次作业 第一次作业由于时间仓促,没有过多的架构设计,就直接补全了所给的MyUmlInteraction类,导致整个程序的代码风格和效率都不高,在强测中也因此失掉 ...

  2. Web/Java Web项目如何模块化?没有正文,别点

    事情是这样的,两三年前做了几个Java Web项目,由于薪资原因,原主程都离开了. 由于公司不规范,也没有留下正规的开发文档,只有一个源程序在手里.后面的很多系统维护都很被动. 领导就觉得说,这样不好 ...

  3. java基础编程——用两个栈来实现一个队列

    题目描述 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 题目代码 /** * <分析>: * 入队:将元素进栈A * 出队:判断栈B是否为空, * ...

  4. axios向后端请求解决跨域问题

    我要向后端的请求的url是 http://192.168.3.25/ productInfo/insert 我是先用niginx转成localhost:8081 找conf/ nginx.conf , ...

  5. 问题003:JDK文件夹下的bin有什么作用?javac.exe和java.exe双击后为什么一闪而过,没了?

    bin (binary)二进制 ,JDK当中所有的可以执行的二进制应用程序都放在其中.其中都是*.exe文件,表示可以直接执行程序. javac.exe和java.exe双击后为什么一闪而过,没了?因 ...

  6. 三十四、MySQL 函数

    MySQL 函数 MySQL 有很多内置的函数,以下列出了这些函数的说明. MySQL 字符串函数 函数 描述 实例 ASCII(s) 返回字符串 s 的第一个字符的 ASCII 码. 返回 Cust ...

  7. matplotlib(一)——matplotlib横轴坐标密集字符覆盖

    一.问题描述 具体问题是: 用python库matplotlib进行数据的图表展示: 图表展示图形横坐标有将近100个自定义值需要显示: 保存矢量图(svg),保存后发现横坐标过于密集,坐标值之间有覆 ...

  8. JZOJ 4757. 树上摩托

    Description Sherco是一位经验丰富的魔♂法师.Sherco在第零次圣杯战争中取得了胜利,并取得了王之宝藏——王の树.他想把这棵树砍去任意条边,拆成若干棵新树,并装饰在他的摩托上,让他的 ...

  9. Python 交互模式中 Delete/Backspace 键乱码问题

    进入 Python 交互模式,按下 Delete/Backspace 键,会出现 ^H 字符 解决方式: 1. 进到 Python 的Modules目录 [root@cyt-test Python-2 ...

  10. Android 服务入门

    前言:硬着头皮把数据库SQLite看完了,接下来就是android服务了,因为自己本身就是菜鸟,所以呢,也只是做做笔记,技术上的东西就别指望我了. 1.什么是服务呢?举个例子,百度地图,美团外卖,OF ...