题目

输入格式

第一行包含一个正整数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. 启动tomcat的Cannot find ./catalina.sh 的问题

    从终端进入tomcat的bin目录,然后执行startup.sh Cannot find bin/catalina.sh The file is absent or does not have exe ...

  2. 多线程:InterlockedIncrement

    1.InterlockedIncrement保护多线程中操作的整数. #include <stdio.h> #include <windows.h> volatile long ...

  3. 使用U盘引导安装CentOS

    一.制作linux引导盘 1. 格式化U盘:格式成FAT32格式 2. 安装syslinux https://www.kernel.org/pub/linux/utils/boot/syslinux/ ...

  4. 操作文件 -------JavaScrip

    本文摘要:http://www.liaoxuefeng.com/ 在HTML表单中,可以上传文件的唯一控件就是<input type="file">. 注意:当一个表单 ...

  5. 初尝微信小程序1-特点

    微信小程序特点:1.不需要下载安装即可使用 2.用户用完即走,不用关心是否安装太多应用 3.应用将无处不在,随时可用 适合开发的小程序类型:1.简单的用完即走的应用 2.低频的应用 3.性能要求不高的 ...

  6. Windows 下编辑 hosts 文件

    hosts 文件目录: C:\WINDOWS\system32\drivers\etc\hosts hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应 ...

  7. 为什么90%的IT人员都不适合做老大?

    什么是格局? 格局就是能够很好的平衡短期利益和长期利益. 过分注重短期利益的人必然会失去长期利益,到头来一定会很普通. 例如:跳槽不断,可能短期薪资会增长,但长期来看后劲可能会不足,未来发展空间会变窄 ...

  8. PHP导出成PDF功能开发教程

    准备工作 首先查询了相关的类库,有FPDF,zendPDF,TcPDF等等.首先看了下先选择了FPDF,可以说除了中文字符以外没有什么问题,中文乱码而且看了下最新版本没有很好的解决方案,所以只能放弃. ...

  9. linux磁盘满了怎么办??删掉无用的大文件

    今天公司网站突然无法访问,因为之前遇到过是因为磁盘问题,所以使用 df 命令查看结果,结果果然是有100%的东西,那么怎么解决呢,我们想到得查找大文件,并删掉无用的大文件比如log 那么linux如何 ...

  10. 数据存储之使用mysql数据库存储数据

    推荐安装mysql5.7环境: 官网下载:https://dev.mysql.com/downloads/installer/5.7.html 如果提示没有.NET Framework框架.那么就在提 ...