题解:

第k大直接用主席树解决

合并利用启发式合并,将较小的连接到较大的树上

 #include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf = 2e9;
const int logn = ;
const int maxn = 8e4 + ;
const int maxm = 2e5;
int t, n, m, q;
int sum[maxn * ], lc[maxn * ], rc[maxn * ];
int rt[maxn];
int tot, nex[maxm], fir[maxm], ver[maxm];
int num, cnt;
int ans;
int disp[maxn];
int si[maxn], dep[maxn], anc[maxn][logn + ];
int fat[maxn];
int val[maxn];
bool vis[maxn];
inline int Get()
{
int x;
char c;
bool o = false;
while((c = getchar()) < '' || c > '')
if(c == '-') o = true;
x = c - '';
while((c = getchar()) >= '' && c <= '')
x = x * + c - '';
return (o) ? -x : x;
}
inline void Reset()
{
for(int i = ; i <= n; ++i)
disp[i] = val[i], fat[i] = i, si[i] = ;
}
inline void Disperse()
{
sort(disp + , disp + + n);
disp[] = -inf;
for(int i = ; i <= n; ++i)
if(disp[i] != disp[i - ])
disp[++num] = disp[i];
for(int i = ; i <= n; ++i)
val[i] = lower_bound(disp + , disp + + num, val[i]) - disp;
}
inline void Ins(int x, int y)
{
nex[++tot] = fir[x], fir[x] = tot, ver[tot] = y;
}
inline int Find(int x)
{
return (fat[x] != x) ? fat[x] = Find(fat[x]) : x;
}
inline void Edge(int x, int y)
{
int a = Find(x), b = Find(y);
if(a != b) fat[a] = b, si[b] += si[a];
Ins(x, y), Ins(y, x);
}
int Add(int p, int l, int r, int v)
{
int k = ++cnt;
sum[k] = sum[p] + ;
if(l == r) return k;
int mi = l + r >> ;
if(v <= mi) lc[k] = Add(lc[p], l, mi, v), rc[k] = rc[p];
else lc[k] = lc[p], rc[k] = Add(rc[p], mi + , r, v);
return k;
}
void Build(int u, int f)
{
vis[u] = true;
dep[u] = dep[f] + ;
anc[u][] = f;
for(int i = ; i <= logn; ++i)
anc[u][i] = anc[anc[u][i - ]][i - ];
rt[u] = Add(rt[f], , num, val[u]);
for(int i = fir[u]; i; i = nex[i])
{
int v = ver[i];
if(v == f) continue;
Build(v, u);
}
}
inline void Edge()
{
for(int i = ; i <= m; ++i) Edge(Get(), Get());
}
inline void Build()
{
for(int i = ; i <= n; ++i)
if(!vis[i])
Build(i, );
}
inline void Link(int x, int y)
{
int a = Find(x), b = Find(y);
if(si[a] < si[b]) swap(x, y);
dep[y] = dep[x] + ;
Build(y, x);
Ins(x, y), Ins(y, x);
}
inline int Lca(int x, int y)
{
if(dep[x] < dep[y]) swap(x, y);
for(int i = logn; i >= ; --i)
if(dep[anc[x][i]] >= dep[y])
x = anc[x][i];
if(x == y) return x;
for(int i = logn; i >= ; --i)
if(anc[x][i] != anc[y][i])
{
x = anc[x][i];
y = anc[y][i];
}
return anc[x][];
}
inline int Query(int a, int b, int c, int d, int l, int r, int k)
{
if(l == r) return disp[l];
int res = sum[lc[a]] + sum[lc[b]] - sum[lc[c]] - sum[lc[d]];
int mi = l + r >> ;
if(res >= k) return Query(lc[a], lc[b], lc[c], lc[d], l, mi, k);
return Query(rc[a], rc[b], rc[c], rc[d], mi + , r, k - res);
}
inline void Ask()
{
while(q--)
{
char c;
while((c = getchar()) != 'L' && c != 'Q');
switch(c)
{
case 'L':
{
int x = Get() ^ ans, y = Get() ^ ans;
Link(x, y);
break;
}
case 'Q':
{
int x = Get() ^ ans, y = Get() ^ ans, k = Get() ^ ans;
int lca = Lca(x, y);
ans = Query(rt[x], rt[y], rt[lca], rt[anc[lca][]], , num, k);
printf("%d\n", ans);
break;
}
}
}
}
int main()
{
t = Get(), n = Get(), m = Get(), q = Get();
for(int i = ; i <= n; ++i) val[i] = Get();
Reset();
Disperse();
Edge();
Build();
Ask();
}

森林 BZOJ 3123的更多相关文章

  1. 【sdoi2013】森林 BZOJ 3123

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

  2. AC日记——[Sdoi2013]森林 bzoj 3123

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

  3. [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)

    [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...

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

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

  5. bzoj 3123: [Sdoi2013]森林(45分暴力)

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

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

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

  7. BZOJ 3123 森林(函数式线段树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3123 题意: 思路:总的来说,查询区间第K小利用函数式线段树的减法操作.对于两棵树的合并 ...

  8. ●BZOJ 3123 [Sdoi2013]森林

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3123 题解: 主席树,在线,启发式合并 简单版(只有询问操作):[2588: Spoj 10 ...

  9. BZOJ 3123 [SDOI2013] 森林 - 启发式合并 主席树

    Description 给你一片森林, 支持两个操作: 查询$x$到$y$的$K$大值,  连接两棵树中的两个点 Solution 对每个节点$x$动态开权值线段树, 表示从$x$到根节点路径上权值出 ...

随机推荐

  1. 系统相册中获取gif图片 保证取到的图片不会改变

    NSURL *imageRefURL = [info valueForKey:UIImagePickerControllerReferenceURL];                         ...

  2. 多进程Queue

    进程间通讯 不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法: Queues 使用方法跟threading里的queue差不多 from multiprocessing impo ...

  3. HTML网页的浏览器标题栏显示小图标的方法

    HTML网页的浏览器标题栏显示小图标的方法   就像这种效果,方法其实很简单,就是 在head头部里写: <link rel='icon' href='pic.ico ' type='image ...

  4. 17条 Swift 最佳实践规范

    本文由CocoaChina译者小袋子(博客)翻译自schwa的github主页原文作者:schwa 这是一篇 Swift 软件开发的最佳实践教程. 前言 这篇文章是我根据在 SwiftGraphics ...

  5. [LUOGU]P1443 马的遍历

    题目描述 有一个n*m的棋盘(1< n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步 输入输出格式 输入格式: 一行四个数据,棋盘的大小和马的坐标 输 ...

  6. [LUOGU] 1892 团伙

    题目描述 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的朋友是我的朋友: 我敌人的敌人也是我的朋友. 两个强盗是同一团伙的 ...

  7. Linux-实现双主模型的nginx的高可用

    实现双主模型的ngnix高可用(一) 准备:主机7台 client: 172.18.x.x 调度器:keepalived+nginx 带172.18.x.x/16 网卡 192.168.234.27 ...

  8. String中indexof函数的用法

    int indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引. int indexOf(int ch, int fromIndex) 从指定的索引开始搜索,返回在此字符串中第一次 ...

  9. Perl学习之四:语句(续)

    循环控制:1.last 退出标签的语句块2.next 3.redo不推荐,循环次数不可控 4.goto不推荐.***************************************标签: 先 ...

  10. Sublime安装与配置

    1.到官网下载Sublime https://www.sublimetext.com/ 2.安装时选择添加到右键菜单 Add to explorer context menu 3.安装插件 菜单 to ...