题解:

第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. PHP高端课程

    关于目后佐道IT教育 http://www.cnblogs.com/itpua/p/7710917.html 目后佐道IT教育的师资团队 http://www.cnblogs.com/itpua/p/ ...

  2. python_109_切片补充和list函数

    #切片补充 a=[1,2,3,4,5,6,7,8] print(a[::2])#隔一个取一个元素 [1, 3, 5, 7] print(a[::-1])#将列表或元祖颠倒过来 [8, 7, 6, 5, ...

  3. java POI技术之导出数据优化(15万条数据1分多钟)

    专针对导出excel2007 ,用到poi3.9的jar package com.cares.ynt.util; import java.io.File; import java.io.FileOut ...

  4. Codeforces Round #271 (Div. 2)-B. Worms

    http://codeforces.com/problemset/problem/474/B B. Worms time limit per test 1 second memory limit pe ...

  5. ios之UIProgressView

    UIProgressView和UIActivityIndicator有些类似   但是不同之处在于, UIProgressView能够更加精确的反应进度 UIActivityIndicator则只能表 ...

  6. ios之UIPickView

    以下为控制器代码,主要用到的是UIPickerView 主要步骤:新建一个Single View Application 然后,如上图所示,拖进去一个UILabel Title设置为导航,再拖进去一个 ...

  7. 【搜索 技巧】Letter gaps

    需要一定技巧的搜索题 题目描述 记得做过这样一道题 Ponder This Challenge: In the string CABACB, each letter appears exactly t ...

  8. [LUOGU]P1443 马的遍历

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

  9. SpringAOP拦截器的代理机制

    要使用方法名匹配AOP切面编程,需要使用到spring中的org.springframework.aop.support.NameMatchMethodPointcutAdvisor这个类,advic ...

  10. docker:安装mysql多个

    文章来源:https://www.cnblogs.com/hello-tl/p/9238298.html 1.首先安装docker 参照一下网址安装docker docker:安装 https://w ...