森林 BZOJ 3123
题解:
第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的更多相关文章
- 【sdoi2013】森林 BZOJ 3123
Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负整数 ...
- AC日记——[Sdoi2013]森林 bzoj 3123
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 3216 Solved: 944[Submit][Status] ...
- [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)
[BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...
- BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]
3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...
- bzoj 3123: [Sdoi2013]森林(45分暴力)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4184 Solved: 1235[Submit][Status ...
- Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...
- BZOJ 3123 森林(函数式线段树)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3123 题意: 思路:总的来说,查询区间第K小利用函数式线段树的减法操作.对于两棵树的合并 ...
- ●BZOJ 3123 [Sdoi2013]森林
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3123 题解: 主席树,在线,启发式合并 简单版(只有询问操作):[2588: Spoj 10 ...
- BZOJ 3123 [SDOI2013] 森林 - 启发式合并 主席树
Description 给你一片森林, 支持两个操作: 查询$x$到$y$的$K$大值, 连接两棵树中的两个点 Solution 对每个节点$x$动态开权值线段树, 表示从$x$到根节点路径上权值出 ...
随机推荐
- UVA 10003 cuting sticks 切木棍 (区间dp)
区间dp,切割dp[i][j]的花费和切法无关(无后效性) dp[i][j]表示区间i,j的花费,于是只要枚举切割方法就行了,区间就划分成更小的区间了.O(n^3) 四边形不等式尚待学习 #inclu ...
- WPF中HyperLink超链接的使用
HyperLink超链接的简单使用: XAML里面: <TextBlock> <Hyperlink NavigateUri="http://www.baidu.com&q ...
- 关于CSS3三角的实现
1,向上的三角 ;; ;; </html> 3,向左的三角 ;; </html> 4,向右的三角 ;; ...
- 看paper的网址
http://www.arxiv-sanity.com/ https://scirate.com/ google搜cvpr open access.iccv open access
- js parse_url 引发的
原文链接:https://www.w3.org/TR/2011/WD-html5-20110525/origin-0.html 这里只是做下记录: 5.3 Origin — HTML5 li, dd ...
- shell脚本,提取ip地址和子网掩码,和查外网ip地址信息。
#提取IP地址和子网掩码 [root@localhost ~]# ifconfig eth0|grep 'inet addr'|awk -F'[ :]+' '{print $4"/& ...
- 不安装oracle客户端用sqlplus连接数据库
在不安装oracle客户端情况下用sqlplus连接数据库: 1.去官网下载 http://www.oracle.com/technetwork/topics/winx64soft-089540.ht ...
- virtualenvwrapper.sh报错: There was a problem running the initialization hooks.解决
由于在ubuntu环境下,将python做与python3.6做了软链接(ln -s python python3.6),并且pip也被我做了软链接,所以导致用pip安装virtualenvwrapp ...
- Luogu 3423 [POI 2005]BAN-银行票据 (多重背包单调队列优化 + 方案打印)
题意: 给出 n 种纸币的面值以及数量,求最少使用多少张纸币能凑成 M 的面额. 细节: 好像是要输出方案,看来很是头疼啊. 分析: 多重背包,裸体??? 咳咳,好吧需要低调,状态就出来了: dp [ ...
- java中ArrayList、LinkedList、Vector的区别
ArrayList.LinkedList.Vector这三个类都实现了List接口. ArrayList是一个可以处理变长数组的类型,可以存放任意类型的对象.ArrayList的所有方法都是默认在单一 ...