对着题目yy了一天加上看了一中午题解,终于搞明白了我太弱了

连边就是合并线段树,把小的集合合并到大的上,可以保证规模至少增加一半,复杂度可以是\(O(logn)\)

合并的时候暴力dfs修改倍增数组和维护主席树即可

然后树上主席树就是维护节点到根节点的信息即可,

询问链上的第k大时,画图后可以发现维护一个rootx,rooty,rootlca和rootfalca即可解决问题

注意空间要开够

然后注意细节,没了

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int vis[100000],root[100000],fa[100000],jump[100000][19],sonnum[100000],u[100000<<2],v[100000<<2],fir[100000],nxt[100000<<2],cnt,dep[100000],midax[100000],w_p[100000],n,m,T,Nodecnt,testcase;
const int MAXlog = 18;
int lastans=0,nx;
struct PTNode{
int sz,lson,rson;
}PT[100000 * 100];
void addedge(int ui,int vi){
++cnt;
u[cnt]=ui;
v[cnt]=vi;
nxt[cnt]=fir[ui];
fir[ui]=cnt;
}
int findroot(int x){
return (fa[x]==x)?x:fa[x]=findroot(fa[x]);
}
int query(int L,int R,int xroot,int yroot,int lcaroot,int falcaroot,int kth){
if(L==R)
return L;
int mid=(L+R)>>1,lch=PT[PT[xroot].lson].sz+PT[PT[yroot].lson].sz-PT[PT[lcaroot].lson].sz-PT[PT[falcaroot].lson].sz;
if(lch<kth)
return query(mid+1,R,PT[xroot].rson,PT[yroot].rson,PT[lcaroot].rson,PT[falcaroot].rson,kth-lch);
else
return query(L,mid,PT[xroot].lson,PT[yroot].lson,PT[lcaroot].lson,PT[falcaroot].lson,kth);
}
void insert(int L,int R,int &now,int c){
PT[++Nodecnt]=PT[now];
now=Nodecnt;
PT[now].sz++;
if(L==R)
return;
int mid=(L+R)>>1;
if(c<=mid)
insert(L,mid,PT[now].lson,c);
else
insert(mid+1,R,PT[now].rson,c);
}
void dfs(int u,int father,int d,int rootu){
dep[u]=d;
vis[u]=1;
fa[u]=father;
jump[u][0]=father;
sonnum[rootu]++;
for(int i=1;i<=MAXlog;i++)
jump[u][i]=jump[jump[u][i-1]][i-1];
int pos = lower_bound(midax+1,midax+nx+1,w_p[u])-midax;
root[u]=root[father];
insert(1,nx,root[u],pos);
for(int i=fir[u];i;i=nxt[i]){
if(v[i]==father)
continue;
dfs(v[i],u,d+1,rootu);
}
}
int lca(int x,int y){
if(dep[x]<dep[y])
swap(x,y);
for(int i=MAXlog;i>=0;i--)
if(dep[x]-(1<<i)>=dep[y])
x=jump[x][i];
if(x==y)
return x;
for(int i=MAXlog;i>=0;i--)
if(jump[x][i]!=jump[y][i])
x=jump[x][i],y=jump[y][i];
return jump[x][0];
}
void link(int x,int y){
addedge(x,y);
addedge(y,x);
int rootx=findroot(x);
int rooty=findroot(y);
if(sonnum[rootx]<sonnum[rooty])
swap(x,y),swap(rootx,rooty);
dfs(y,x,dep[x]+1,rootx);
x+=sonnum[y];
}
int main(){
scanf("%d",&testcase);
scanf("%d %d %d",&n,&m,&T);
for(int i=1;i<=n;i++)
scanf("%d",&w_p[i]),midax[i]=w_p[i],fa[i]=i;
nx=unique(midax+1,midax+n+1)-midax-1;
sort(midax+1,midax+nx+1);
for(int i=1;i<=m;i++){
int a,b;
scanf("%d %d",&a,&b);
addedge(a,b);
addedge(b,a);
}
for(int i=1;i<=n;i++)
if(!vis[i]){
dfs(i,0,0,i);
fa[i]=i;
}
for(int i=1;i<=T;i++){
char opt=getchar();
while(opt!='Q'&&opt!='L')
opt=getchar();
if(opt=='Q'){
int x,y,k;
scanf("%d %d %d",&x,&y,&k);
x^=lastans;
y^=lastans;
k^=lastans;
// printf("lca(%d,%d) = %d\n",x,y,lca(x,y));
lastans=midax[query(1,nx,root[x],root[y],root[lca(x,y)],root[jump[lca(x,y)][0]],k)];
printf("%d\n",lastans);
}
else{
int x,y;
scanf("%d %d",&x,&y);
x^=lastans;
y^=lastans;
link(x,y);
}
}
return 0;
}

p3302 [SDOI2013]森林(树上主席树+启发式合并)的更多相关文章

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

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

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

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

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

    BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20 ...

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

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

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

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

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

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

  7. [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+启发式合并)

    传送门 突然发现好像没有那么难……https://blog.csdn.net/stone41123/article/details/78167288 首先有两个操作,一个查询,一个连接 查询的话,直接 ...

  8. [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)

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

  9. 【BZOJ-3123】森林 主席树 + 启发式合并

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

随机推荐

  1. Spark学习之路 (十四)SparkCore的调优之资源调优JVM的GC垃圾收集器

    一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...

  2. 前端和后台BUG区分方法

    测试工程师不只是负责发现问题,除了发现问题这种基本功外,定位问题,提出解决方案,提出预防方案也是要掌握的技能.这里先说定位问题的要求,定位问题要向深入,前提当然是对功能.产品的流程.开发方案.开发人员 ...

  3. django的母板和继承

    Django模板中只需要记两种特殊符号: {{  }}和 {% %} {{ }}表示变量,在模板渲染的时候替换成值,{% %}表示逻辑相关的操作. 母板 <!DOCTYPE html> & ...

  4. greenplum presto impala选型与测评

    查看原文请至:https://my.oschina.net/hblt147/blog/1843028

  5. Qt 之 模态、非模态、半模态窗口的介绍及 实现QDialog的exec()方法

    一.简述 先简单介绍一下模态与非模态对话框. 模态对话框 简单一点讲就是在弹出模态对话框时,除了该对话框整个应用程序窗口都无法接受用户响应,处于等待状态,直到模态对话框被关闭.这时一般需要点击对话框中 ...

  6. C++中set用法详解

    1.关于set C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构 ...

  7. onclick 常用手册

    1.如何去使用onclick来跳转到我们指定的页面/跳转到指定url ☆如果只是在本页显示的话,可以直接用location, 方法如下: ①onclick="javascript:windo ...

  8. Inernet TLS协议注册表 开启

    IE高级配置中,存在SSL支持协议,例如SSL TLS. 其在注册表的路径为:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\I ...

  9. JS中常见原生DOM操作API

    摘自:https://blog.csdn.net/hj7jay/article/details/53389522 几种对象 Node Node是一个接口,中文叫节点,很多类型的DOM元素都是继承于它, ...

  10. linux git 报错提示 fatal: 'origin' does not appear to be a git repository 解决办法

    输入: git pull origin master git报错提示 fatal: 'origin' does not appear to be a git repository fatal: Cou ...