Description

Input

第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
 接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。

Output

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

Sample Input

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

Sample Output

2
2
1
4
2

HINT

对于第一个操作 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。之后的操作类似。

【思路】

主席树+倍增lca+启发式合并

如果没有连边操作的话就是luo主席树。两棵树要相连,那一棵在上面无所谓,因为我们要遍历处于下方的树的所有节点所以我们采用启发式合并,即每次选择结点数更小的树放在下面,然后重建每一个结点。

【代码】

 #include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; const int N = ;
const int M = *N;
const int D = ; struct Tnode {
int sum,lc,rc;
} T[M]; int n,m,q,sz,rt[N];
int p[N],siz[N];
int fa[N][D],hash[N],dep[N];
int v[N],tot;
vector<int> g[N]; void read(int& x) {
char c=getchar();
int f=;x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
x*=f;
} int ifind(int u)
{
while(fa[u][]) u=fa[u][];
return u;
}
void insert(int l,int r,int x,int& y,int num)
{
T[y=++sz]=T[x]; T[y].sum++;
if(l==r) return ;
int mid=(l+r)>>;
if(num<=mid) insert(l,mid,T[x].lc,T[y].lc,num);
else insert(mid+,r,T[x].rc,T[y].rc,num);
}
void dfs(int u,int f)
{
dep[u]=dep[f]+; fa[u][]=f; siz[u]=;
insert(,tot,rt[f],rt[u],v[u]);
FOR(i,,D-) //p1
fa[u][i]=fa[fa[u][i-]][i-];
FOR(i,,(int)g[u].size()-) {
int v=g[u][i];
if(v!=f) {
dfs(v,u);
siz[u]+=siz[v];
}
}
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int t=dep[u]-dep[v];
FOR(j,,D-)
if(t&(<<j)) u=fa[u][j];
if(u==v) return u;
for(int j=D-;j>=;j--)
if(fa[u][j]!=fa[v][j]) u=fa[u][j],v=fa[v][j];
return fa[u][];
}
int query(int l,int r,int a,int b,int c,int d,int rk)
{
if(l==r) return l;
int mid=(l+r)>>;
int now=T[T[a].lc].sum+T[T[b].lc].sum-T[T[c].lc].sum-T[T[d].lc].sum;
if(rk<=now) return query(l,mid,T[a].lc,T[b].lc,T[c].lc,T[d].lc,rk);
else return query(mid+,r,T[a].rc,T[b].rc,T[c].rc,T[d].rc,rk-now);
}
int query(int x,int y,int z)
{
int c=lca(x,y);
return query(,tot,rt[x],rt[y],rt[c],rt[fa[c][]],z);
} int main()
{
int kase; read(kase);
read(n),read(m),read(q);
FOR(i,,n) {
read(v[i]); hash[i]=v[i];
fa[i][]=;
}
sort(hash+,hash+n+);
tot=unique(hash+,hash+n+)-hash-;
FOR(i,,n)
v[i]=lower_bound(hash+,hash+tot+,v[i])-hash;
char op[];
int ans=,x,y,z;
FOR(i,,m) {
read(x),read(y);
g[x].push_back(y);
g[y].push_back(x);
}
FOR(i,,n) if(!fa[i][]) dfs(i,);
FOR(i,,q) {
scanf("%s",op);
read(x),read(y);
x^=ans; y^=ans;
if(op[]=='Q') {
read(z);
z^=ans;
printf("%d\n",ans=hash[query(x,y,z)]);
} else {
int fx=ifind(x),fy=ifind(y);
if(siz[fx]<siz[fy])
swap(fx,fy),swap(x,y);
siz[fx]+=siz[fy];
g[x].push_back(y);
g[y].push_back(x);
dfs(y,x);
}
}
return ;
}

bzoj 3123 [Sdoi2013]森林(主席树,lca,启发式合并)的更多相关文章

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

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

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

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

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

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

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

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

  5. bzoj 3123 [Sdoi2013]森林(主席树+启发式合并+LCA)

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

  6. 【BZOJ3123】[Sdoi2013]森林 主席树+倍增LCA+启发式合并

    [BZOJ3123][Sdoi2013]森林 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整 ...

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

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

  8. ●BZOJ 3123 [Sdoi2013]森林

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

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

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

随机推荐

  1. [转载]MongoDB设置访问权限、设置用户

    MongoDB已经使用很长一段时间了,基于MongoDB的数据存储也一直没有使用到权限访问(MongoDB默认设置为无权限访问限制),今天特地花了一点时间研究了一下,研究成果如下: 注:研究成果基于W ...

  2. Jenkins任务启动的后台进程被自动kill

    在Jenkins的使用中,遇到过的一个场景是:在web代码更改之后,能自动的部署到测试服务器,我们写了run.sh脚本来重启服务,在使用Jenkins的任务自动跑这个脚本后发现,服务没有起来.开始以为 ...

  3. Deployment of VC2008 apps without installing anything

    If you create a default CRT/MFC application with VS2008, this application will not run on other comp ...

  4. PHP 怎么随机获取数组里面的值

    注意array_rand随机返回的是KEY值的集合 <?php srand((float) microtime() * 10000000); $input = array("Neo&q ...

  5. Oracle Exception 处理

    1.问题来源Oracle中可以用dbms_output.put_line来打印提示信息,但是很容易缓冲区就溢出了.可以用DBMS_OUTPUT.ENABLE(1000000);来设置缓冲区的大小.但是 ...

  6. 一步一步制作yaffs/yaffs2根文件系统(二)---安装BusyBox,构造/bin、/sbin、/usr、linuxr

    开发环境:Ubuntu 12.04 开发板:mini2440  256M NandFlash   64M SDRAM 交叉编译器:arm-linux-gcc 4.4.3点此可下载 BusyBox版本: ...

  7. SharePoint2013切换帐户登录菜单

    SharePoint2013帐户姓名显示的地方没有切换帐户的菜单,这个功能对于终端用户是可有可无的,但对于sharepoint管理员或sharepoint开发人员来讲,却是一个很重要的菜单,由于经常要 ...

  8. js createElement

      http://www.w3schools.com/js/js_htmldom_nodes.asp var child = document.getElementById("p1" ...

  9. Android 之 内存管理-查看内存泄露(三)

    概述 在android的开发中,要时刻主要内存的分配和垃圾回收,因为系统为每一个dalvik虚拟机分配的内存是有限的,在google的G1中,分配的最大堆大小只有16M,后来的机器一般都为24M,实在 ...

  10. bzoj1029

    贪心,比较明显了(很像USACO的风格); 按时间限制排序(升序) 顺次处理,如果当前时间能够修复就修复 否则就在之前修复的任务中找一个耗时最多(大于当前任务)的,改成修当前任务; 显然这样最优吧, ...