首先对于查询操作就是裸的COT QAQ

在树上DFS建出主席树就可以了

对于连接操作,我们发现并没有删除

所以我们可以进行启发式合并,每次将小的树拍扁插入大的树里并重构即可

写完了之后第一个和第二个点迷のRE

然后又重新写了一遍就A了(并不知道为什么,难道第一遍写挫了?

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std; const int maxn=100010;
int T,n,m,Q,u,v,k,lca,w;
int ans=0;
char ch;
int p[maxn];
int fa[maxn],dep[maxn],sz[maxn];
int anc[maxn][20];
int h[maxn],cnt=0;
struct edge{
int to,next;
}G[maxn<<1];
void add(int x,int y){++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;}
int ufs(int x){return fa[x]==x?x:fa[x]=ufs(fa[x]);} int a[maxn];
struct val{
int v,id;
}c[maxn];
bool cmpv(const val &A,const val &B){return A.v<B.v;}
bool cmpid(const val &A,const val &B){return A.id<B.id;} int tot=0,rt[maxn];
struct Seg_Tree{
int L,R,v;
}t[11000010]; void read(int &num){
num=0;ch=getchar();
while(ch<'!')ch=getchar();
while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
}
void build(int &o,int L,int R){
o=++tot;
if(L==R)return;
int mid=(L+R)>>1;
build(t[o].L,L,mid);
build(t[o].R,mid+1,R);
}
void modify(int &o,int now,int L,int R,int p){
t[++tot]=t[now];o=tot;
if(L==R){t[o].v++;return;}
int mid=(L+R)>>1;
if(p<=mid)modify(t[o].L,t[now].L,L,mid,p);
else modify(t[o].R,t[now].R,mid+1,R,p);
t[o].v=t[t[o].L].v+t[t[o].R].v;
}
void DFS(int u,int f){
anc[u][0]=f;
modify(rt[u],rt[f],1,m,c[u].v);
for(int i=1;i<=18;++i){
if(anc[u][i-1]!=0){
int a=anc[u][i-1];
anc[u][i]=anc[a][i-1];
}else anc[u][i]=0;
}
for(int i=h[u];i;i=G[i].next){
int v=G[i].to;
if(v==f)continue;
dep[v]=dep[u]+1;
DFS(v,u);
}return;
}
int LCA(int p,int q){
if(dep[p]<dep[q])swap(p,q);
int d=dep[p]-dep[q];
for(int i=18;i>=0;--i){
if(d>>i&1)p=anc[p][i];
}
if(p==q)return p;
for(int i=18;i>=0;--i){
if(anc[p][i]!=anc[q][i]&&anc[p][i]!=0)p=anc[p][i],q=anc[q][i];
}return anc[p][0];
}
int ask(int u,int v,int lca,int L,int R,int k){
if(L==R)return L;
int mid=(L+R)>>1;
int now=t[t[u].L].v+t[t[v].L].v-2*t[t[lca].L].v+(w<=mid&&w>=L);
if(k>now)return ask(t[u].R,t[v].R,t[lca].R,mid+1,R,k-now);
else return ask(t[u].L,t[v].L,t[lca].L,L,mid,k);
}
int main(){
read(T);read(n);read(m);read(Q);
for(int i=1;i<=n;++i)read(c[i].v),c[i].id=i,a[i]=c[i].v;
for(int i=1;i<=n;++i)fa[i]=i;
for(int i=1;i<=m;++i){
read(u);read(v);
add(u,v);add(v,u);
int d1=ufs(u),d2=ufs(v);
if(d1!=d2)fa[d1]=d2;
}m=0;
sort(c+1,c+n+1,cmpv);sort(a+1,a+n+1);
for(int i=1;i<=n;++i){
if(i==1||a[i]!=a[i-1])c[i].v=++m,p[m]=a[i];
else c[i].v=m;
}
sort(c+1,c+n+1,cmpid);
build(rt[0],1,m);
for(int i=1;i<=n;++i){
if(ufs(i)==i)DFS(i,0);
sz[ufs(i)]++;
}
while(Q--){
ch=getchar();
while(ch<'!')ch=getchar();
if(ch=='Q'){
scanf("%d%d%d",&u,&v,&k);
u^=ans;v^=ans;k^=ans;
lca=LCA(u,v);w=c[lca].v;
//cout<<u<<' '<<v<<' '<<k<<endl;
ans=p[ask(rt[u],rt[v],rt[lca],1,m,k)];
printf("%d\n",ans);
}else{
scanf("%d%d",&u,&v);
u^=ans;v^=ans;
//cout<<u<<' '<<v<<endl;
int d1=ufs(u),d2=ufs(v);
//cout<<d1<<' '<<d2<<endl;
if(sz[d1]<sz[d2])swap(u,v),swap(d1,d2);
sz[d1]+=sz[d2];
if(d1!=d2)fa[d2]=d1;//d2->d1
dep[v]=dep[u]+1;
DFS(v,u);add(u,v);add(v,u);
}
}return 0;
}

  

BZOJ 3123 SDOI2013 森林的更多相关文章

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

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

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

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

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

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

  4. ●BZOJ 3123 [Sdoi2013]森林

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

  5. BZOJ 3123 [SDOI2013] 森林 - 启发式合并 主席树

    Description 给你一片森林, 支持两个操作: 查询$x$到$y$的$K$大值,  连接两棵树中的两个点 Solution 对每个节点$x$动态开权值线段树, 表示从$x$到根节点路径上权值出 ...

  6. bzoj 3123 [Sdoi2013]森林(主席树,lca,启发式合并)

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

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

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

  8. 3123: [Sdoi2013]森林

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

  9. 【BZOJ】3123: [Sdoi2013]森林

    题解 ------------------ 我莫不是一个智障吧 我把testdata的编号 当成数据组数读进来 我简直有毒 以为哪里写错了自闭了好久 实际上这题很简单,只要愉悦地开个启发式合并,然后每 ...

随机推荐

  1. c# using 引用和别名的使用

    1.使用别名 在同时引用的两个命名空间中有相同的类型时,可以使用别名来区分.如下所示: using System; using System.Threading; using System.Timer ...

  2. ASP.NET MVC3 使用kindeditor编辑器获取不到值

    做开发真的是会遇到各种问题,如果不亲自尝试,不动手,很难发现问题. 下面我们说下在MVC中的用法 1,首先引入js文件 <script type="text/javascript&qu ...

  3. 在O(1)时间删除链表结点

    题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. 链表结点与函数的定义如下: struct ListNode { int m_nValue; ListNode* m_p ...

  4. [GeekBand] 面向对象的设计模式(C++)(2)

    本篇笔记紧接上篇,继续学习设计模式. 4. 对象创建类设计模式 通过对象创建模式绕开new,来避免对象创建(new)过程中所导致的紧耦合,从而支持对象创建的稳定.它是接口抽象之后的第一步工作. 4.1 ...

  5. OOP—还原被遮掩的继承名称

    1.public继承——using 声明式 class Base { private: int x; public: ; virtual void mf1(int) ; virtual void mf ...

  6. GDI+绘制文本

    这是在论坛中有人提出的一个问题,原贴见:Graphics DrawString参数无效.这里给出方法,读者可以自行修改以适应自己的项目需求. 先上代码: if (!Page.IsPostBack) { ...

  7. Linux下SCP的使用

    一.下载远程文件到本地 scp -i /Users/user/ssh/id_rsa root@192.168.1.8:/root/talk_server_redis/dump.rdb /Users/k ...

  8. ECSHOP 商品页详情页 添加同类随机商品

    1,根目录下找到goods.php文件 找到代码  $smarty->assign('properties',          $properties['pro']);             ...

  9. what is the virtual machine, when and why we need use it ?

    虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的.运行在一个完全隔离环境中的完整计算机系统. 通过虚拟机软件,你可以在一台物理计算机上模拟出二台或多台虚拟的计算机,这些虚 ...

  10. 一些shell脚本实例

    在群里也混了不少时间了.总结一些实例 #统计QQ消息里面某个用户改名字的记录# awk -f# 聊改名字记录#特殊例子 例如#2013-11-28 9:23:56 北京-AA-Vip<12345 ...