首先对于查询操作就是裸的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. (转)Linux下tomcat JVM内存设置步骤

    java.lang.OutOfMemoryError: PermGen space java.lang.OutOfMemoryError: Java heap space -------------- ...

  2. JAVA解析XML的四种方式

    java解析xml文件四种方式 1.介绍 1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这 ...

  3. 打开shpfile,mdb,sde工作空间

    打开shapefile工作空间: ESRI.ArcGIS.Geodatabase.IWorkspaceFactory wsf = new ESRI.ArcGIS.DataSourcesFile.Sha ...

  4. Paying for upgrades, by Bob Arnson

    Following content is reprinted from here, please go to the original website for more information. Au ...

  5. Poj OpenJudge 百练 1860 Currency Exchang

    1.Link: http://poj.org/problem?id=1860 http://bailian.openjudge.cn/practice/1860 2.Content: Currency ...

  6. C语言中fgetc、fputc和getc、putc的区别是什么

    看书的时候,发现了这四个函数,想知道他们的不同.结果上网查发现很多人说fgetc.fputc的f代表的是file,就是这两个函数是和文件有关的!但是一看他们的函数声明,如下图: 发现他们的参数里面都有 ...

  7. Java调用CMD命令

    java的Runtime.getRuntime().exec(commandStr)可以调用执行cmd指令. cmd /c dir 是执行完dir命令后关闭命令窗口. cmd /k dir 是执行完d ...

  8. nginx 配置文件

    #基于ip设置 server{ listen 80; server_name 192.168.116.129; location /{ root /usr/etc/ngin/html/ip; inde ...

  9. Django设置

    运行 django-admin.py startproject [project-name] 命令会生成一系列文件,在Django 1.6版本以后的 settings.py 文件中有以下语句: # B ...

  10. 【生活】已经从官网购买iPad,单独购买AppleCare+服务

    1 什么是AppleCare+服务 从苹果官网购买的硬件产品如ipad.iphone和MacBook等,官网承诺的保修期限是一年.AppleCare+是水果公司推出的一种保修服务,最大的特点就是将保修 ...