BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并

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。之后的操作类似。


考虑没有连边操作怎么做,直接树上主席树就可以。

发现没有删边操作,可以用一个实用的方法:启发式合并。

就是每次把小的那边暴力一个一个拆到大的那边。

实现起来还挺简单的。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
#define N 80050
int head[N],to[N<<1],nxt[N<<1],cnt,root[N],bl[N],f[20][N],Lg[N],n,m,val[N],V[N],dep[N],tot,vv;
int t[N*250],ls[N*250],rs[N*250],siz[N];
inline void add(int u,int v) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void insert(int l,int r,int v,int &y,int x) {
if(!y) y=++tot; t[y]=t[x]+1;
if(l==r) return ;
int mid=(l+r)>>1;
if(v<=mid) rs[y]=rs[x],insert(l,mid,v,ls[y],ls[x]);
else ls[y]=ls[x],insert(mid+1,r,v,rs[y],rs[x]);
}
int qk(int l,int r,int a,int b,int c,int d,int k) {
if(l==r) return V[l];
int mid=(l+r)>>1;
int sizls=t[ls[a]]+t[ls[b]]-t[ls[c]]-t[ls[d]];
if(k<=sizls) return qk(l,mid,ls[a],ls[b],ls[c],ls[d],k);
else return qk(mid+1,r,rs[a],rs[b],rs[c],rs[d],k-sizls);
}
void dfs(int x,int y,int anc) {
dep[x]=dep[y]+1;
siz[anc]++;
bl[x]=anc;
f[0][x]=y;
int i;
insert(1,vv,val[x],root[x],root[y]);
for(i=1;i<=19;i++) f[i][x]=f[i-1][f[i-1][x]];
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y) {
dfs(to[i],x,anc);
}
}
}
int lca(int x,int y) {
int i;
if(dep[x]<dep[y]) swap(x,y);
for(i=Lg[n];i>=0;i--) if(f[i][x]&&dep[f[i][x]]>=dep[y]) x=f[i][x];
if(x==y) return x;
for(i=Lg[n];i>=0;i--) if(f[i][x]&&f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
return f[0][x];
}
void solve() {
// memset(t,0,sizeof(t));
// memset(ls,0,sizeof(ls));
// memset(rs,0,sizeof(rs));
// memset(head,0,sizeof(head)); cnt=0;
// memset(dep,0,sizeof(dep));
int i;
int Q;
scanf("%d%d%d",&n,&m,&Q);
for(Lg[0]=-1,i=1;i<=n;i++) Lg[i]=Lg[i>>1]+1;
int x,y;
for(i=1;i<=n;i++) scanf("%d",&val[i]),V[i]=val[i];
sort(V+1,V+n+1);
vv=unique(V+1,V+n+1)-V-1;
for(i=1;i<=n;i++) val[i]=lower_bound(V+1,V+vv+1,val[i])-V;
for(i=1;i<=m;i++) {
scanf("%d%d",&x,&y); add(x,y); add(y,x);
}
for(i=1;i<=n;i++) {
if(!f[0][i]) dfs(i,0,i);
}
int k,ans=0;
char opt[3];
while(Q--) {
scanf("%s%d%d",opt,&x,&y);
x^=ans; y^=ans;
if(opt[0]=='Q') {
scanf("%d",&k); k^=ans;
int l=lca(x,y);
// printf("%d\n",l);
printf("%d\n",ans=qk(1,vv,root[x],root[y],root[l],root[f[0][l]]?root[f[0][l]]:0,k));
}else {
if(siz[bl[x]]>siz[bl[y]]) swap(x,y);
f[0][x]=y; dep[x]=dep[y]+1;
dfs(x,y,bl[y]); add(x,y); add(y,x);
}
}
}
int main() {
scanf("%*d");
solve();
}
/*
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
*/

BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并的更多相关文章

  1. P3302 [SDOI2013]森林(主席树+启发式合并)

    P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...

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

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

  3. BZOJ2123 [Sdoi2013]森林 【主席树 + 启发式合并】

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

  4. bzoj3123 [Sdoi2013]森林 树上主席树+启发式合并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3123 题解 如果是静态的查询操作,那么就是直接树上主席树的板子. 但是我们现在有了一个连接两棵 ...

  5. [luoguP3302] [SDOI2013]森林(主席树 + 启发式合并 + lca)

    传送门 显然树上第k大直接主席树 如果连边的话,我们重构小的那一棵,连到另一棵上. 说起来简单,调了我一晚上. 总的来说3个错误: 1.离散化写错位置写到了后面 2."="写成了& ...

  6. [bzoj3123][Sdoi2013]森林_主席树_启发式合并

    森林 bzoj-3123 Sdoi-2013 题目大意:给定一片共n个点的森林,T个操作,支持:连接两个不在一棵树上的两个点:查询一棵树上路径k小值. 注释:$1\le n,T \le 8\cdot ...

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

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

  8. 【主席树 启发式合并】bzoj3123: [Sdoi2013]森林

    小细节磕磕碰碰浪费了半个多小时的时间 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M ...

  9. [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT

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

随机推荐

  1. vue-router 的URL路径中#的意义

    传送门 https://router.vuejs.org/zh-c... Router 构造配置 routes 类型: Array<RouteConfig> RouteConfig 的类型 ...

  2. Java HashMap学习笔记

    1.HashMap数据结构 在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外.HashMap实际 ...

  3. apk 签名

    给apk签名步骤:(比方apk名称是EasyMsg.apk) (1)将EasyMsg.apk包后缀改为zip, EasyMsg.zip (2)删除EasyMsg.zip文件包中的META-INF目录, ...

  4. C#对象实例化

    C#常用的对象实例化有以下几种方式: using System; using System.Collections.Generic; using System.Linq; using System.R ...

  5. 如何把网页或html内容生成图片

    网页或html内容生成图片 今天想把做好的html内容或网页生成一张图片,没有网页在线版的生成或转换工具,除非下载客户端软件使用.   不过,发现可以利用搜狗高速浏览器和360浏览器生成图片,这里讲解 ...

  6. Codeforces Round #267 (Div. 2) B. Fedor and New Game

    After you had helped George and Alex to move in the dorm, they went to help their friend Fedor play ...

  7. mysql优化之索引建立的规则

    索引经常使用的数据结构为B+树.结构例如以下 如上图,是一颗b+树,关于b+树的定义能够參见B+树,这里仅仅说一些重点.浅蓝色的块我们称之为一个磁盘块,能够看到每一个磁盘块包括几个数据项(深蓝色所看到 ...

  8. API网关如何实现对服务下线实时感知

    上篇文章<Eureka 缓存机制>介绍了Eureka的缓存机制,相信大家对Eureka 有了进一步的了解,本文将详细介绍API网关如何实现服务下线的实时感知. 一.前言 在基于云的微服务应 ...

  9. Spring LDAP

    LDAP Spring LDAP 使用 - Sayi像秋天一样优雅 - 开源中国社区 http://docs.spring.io/spring-ldap/docs/current/reference/ ...

  10. 各浏览器对常用或者错误的 Content-Type 类型处理方式不一致

    标准参考 content-type 用于定义用户的浏览器或相关设备如何显示将要加载的数据,或者如何处理将要加载的数据,此属性的值可以查看 MIME 类型. MIME (Multipurpose Int ...