对着题目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. 如何重置Sitecore CMS中的管理员密码

    在Sitecore项目上工作时,有时管理员凭据会丢失或损坏.在这些情况下,重新获得快速访问权限以便不中断开发非常重要. 对Core数据库运行以下查询,您将能够admin/b再次使用以下命令登录Site ...

  2. 设置Source Insight显示格式

    调整字体大小 默认的忍不了,百度之,解决方案如下:1.Document Options -> Screen Fonts -> 字体设置为新宋体(等宽)或者其他支持中文的字体,字符集选GB2 ...

  3. RPC框架小结

    为什么说要搞定微服务架构,先搞定RPC框架? 1. 为什么说要搞定微服务架构,先搞定RPC框架? 如果没有统一的服务框架,RPC框架,各个团队的服务提供方就需要各自实现一套序列化.反序列化.网络框架. ...

  4. JustOj 1415: 字符串解压

    题目描述 豆豆非常调皮,总喜欢把一样的东西摆在一起,然后用神奇的猫爪功把他们揉成一团. 比如一堆A,就会被揉成个数+A. 这就是豆豆的字符串压缩算法了. 比如给豆豆一个字符串:ABBCCCDDDDEE ...

  5. python smtplib 发送邮件简单介绍

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式python的smtplib提供了一种很 ...

  6. USB设备被识别流程

    源:   USB设备被识别流程

  7. right spindle supply short to gnd

    hardware guy found that the R1004 lead to this error, but this error should not be checked, because ...

  8. 线程池demo

    package test; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callabl ...

  9. Oracle笔记 #01# 简单分页

    rownum是Oracle为查询结果分配的有序编号(总是从1~n).言下之意,rownum字段本来并不存在于表中,而是经查询后才分配的. 举一个例子: SELECT rownum, name, pri ...

  10. Eloquent JavaScript #13# HTTP and Forms

    索引 Notes fetch form focus Disabled fields form’s elements property 阻止提交 快速插入单词 实时统计字数 监听checkbox和rad ...