题目链接:森林

  这道题想法很显然。既然只有加边而没有删边,那么每次启发式合并就可以了。查询路径\(k\)小似乎需要主席树,那么把主席树和倍增表一起暴力重构就好了。

  然后发现这样的空间复杂度是\(O(n\log^2n)\)的。感觉非常不靠谱,于是滚去写了个节点回收站……然后发现主席树节点回收的话每个节点会被\(dfs\)到多次,还需要一些特判……

  然后就是一直\(RE\)……由于题目是强制在线的那么就应该是\(Wa\)了。但是对拍了\(6W\)组数据没出错我还能说什么呢……

  最后突然发现,我的倍增表在合并的时候好像没有清空……本来以为这样不会出问题,但是由于我的倍增的一些写法,就跳到了一些奇怪的节点上去……以后还是不那么写了,老老实实从上界开始\(for\)吧

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 80010
#define MAXN 1500010 using namespace std;
typedef long long llg; int n,m,T,d[maxn],ld,rt[maxn],a[maxn],qz,lans;
int head[maxn],next[maxn<<1],to[maxn<<1],tt;
int sumv[MAXN],le[MAXN],ri[MAXN],q[MAXN],lq,rq,L;
int f[maxn][17],dep[maxn],fa[maxn],siz[maxn];
bool isin[MAXN]; int getint(){
int w=0;bool q=0;
char c=getchar();
while((c>'9'||c<'0')&&c!='-') c=getchar();
if(c=='-') c=getchar(),q=1;
while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
return q?-w:w;
} int find(int x){return fa[fa[x]]==fa[x]?fa[x]:fa[x]=find(fa[x]);}
void qpush(int x){if(isin[x]) return; isin[x]=1;q[rq++]=x,rq%=MAXN;}
int qtop(){
if(lq==rq) return ++qz;
int now=q[lq++]; lq%=MAXN;
isin[now]=0; return now;
} void link(int x,int y){
to[++tt]=y;next[tt]=head[x];head[x]=tt;
to[++tt]=x;next[tt]=head[y];head[y]=tt;
} int build(int u,int l,int r){
int now=qtop(),mid=(l+r)>>1;
le[now]=le[u]; ri[now]=ri[u];
sumv[now]=sumv[u]+1;
if(l!=r){
if(L<=mid) le[now]=build(le[u],l,mid);
else ri[now]=build(ri[u],mid+1,r);
}
return now;
} void dfs(int u,int fr){
dep[u]=dep[fr]+1; f[u][0]=fr;
if(!fa[u]) fa[u]=(fr?find(fr):u); siz[find(u)]++;
L=a[u],rt[u]=build(rt[fr],1,ld);
for(int i=1;i<17;i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=next[i])
if(to[i]!=fr) dfs(to[i],u);
} void del(int u){if(!u || isin[u])return;qpush(u);del(le[u]);del(ri[u]);le[u]=ri[u]=0;}
void shan(int u,int fr){
del(rt[u]);
for(int i=head[u];i;i=next[i])
if(to[i]!=fr) shan(to[i],u);
} int lca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
for(int i=16;i>=0;i--)
if(dep[f[u][i]]>=dep[v])
u=f[u][i];
if(u==v) return u;
for(int i=16;i>=0;i--)
if(f[u][i]!=f[v][i])
u=f[u][i],v=f[v][i];
return f[u][0];
} void merge(int x,int y){
int a=find(x),b=find(y);
if(siz[a]>siz[b]) swap(x,y),swap(a,b);
fa[a]=b; siz[b]+=siz[a];
shan(a,0); link(x,y); dfs(x,y);
} int query(int x,int y,int k){
int p=lca(x,y),l=1,r=ld,mid,now,g;
x=rt[x]; y=rt[y]; g=rt[p];
while(l!=r){
mid=(l+r)>>1; now=(a[p]>=l && a[p]<=mid);
now+=sumv[le[x]]+sumv[le[y]]-(sumv[le[g]]<<1);
if(k<=now) r=mid,x=le[x],y=le[y],g=le[g];
else k-=now,l=mid+1,x=ri[x],y=ri[y],g=ri[g];
}
return l;
} int main(){
File("a");
getint();
n=getint(); m=getint(); T=getint();
for(int i=1;i<=n;i++) d[++ld]=a[i]=getint();
sort(d+1,d+ld+1); ld=unique(d+1,d+ld+1)-d-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(d+1,d+ld+1,a[i])-d;
while(m--) link(getint(),getint());
for(int i=1;i<=n;i++) if(!dep[i]) dfs(i,0);
while(T--){
char c=getchar(); int x,y;
while(c!='Q' && c!='L') c=getchar();
x=getint()^lans,y=getint()^lans;
if(c=='L') merge(x,y);
else printf("%d\n",lans=d[query(x,y,getint()^lans)]);
}
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 森林

    首先对于查询操作就是裸的COT QAQ 在树上DFS建出主席树就可以了 对于连接操作,我们发现并没有删除 所以我们可以进行启发式合并,每次将小的树拍扁插入大的树里并重构即可 写完了之后第一个和第二个点 ...

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

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

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

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

  9. 3123: [Sdoi2013]森林

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

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

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

随机推荐

  1. 【BZOJ2217】[Poi2011]Lollipop 乱搞

    [BZOJ2217][Poi2011]Lollipop Description 有一个长度为n的序列a1,a2,...,an.其中ai要么是1("W"),要么是2("T& ...

  2. 如何学习 cocos2d-x ?

    发表于 04/23/2014 作者 zrong — 24 条评论 ↓ 11,687 次查看 本站文章除注明转载外,均为本站原创或者翻译. 本站文章欢迎各种形式的转载,但请18岁以上的转载者注明文章出处 ...

  3. AndroidStudio build.gradle 报错

    Android Studio. I'm getting this kind of error during application run. Error:Execution failed for ta ...

  4. 【Android】Android内存溢出问题---用自行开辟的空间进行对内存管理

    public static Bitmap readBitmap(String path) { BitmapFactory.Options options = new BitmapFactory.Opt ...

  5. ubuntu win7双系统设置开机启动顺序

    ctrl+alt+t打开命令终端 sudo chmod +w /boot/grub/grub.cfg (赋予该文件写权限) sudo gedit /boot/grub/grub.cfg 将set de ...

  6. HRBUST - 1153 意外 HRBUST - 1153 (数论)

    意外 Time Limit: 1000 MS Memory Limit: 65536 K Total Submit: 326(87 users) Total Accepted: 97(63 users ...

  7. HDU 4247 Pinball Game 3D(cdq 分治+树状数组+动态规划)

    Pinball Game 3D Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  8. IIS中User-mode caching引起的Cache-Control不为public的问题

    在IIS的Output caching中如果启用了User-mode caching将引起Cache-Control为no-cache,从而造成页面不能被浏览器或代理服务器缓存. web.config ...

  9. 前端程序员:月薪 5K 到 5 万

    入行行头:5 大硬件 请准备好以下东西 一颗人类的大脑:智商在平均水平线以上即可 一份强烈的渴望:我的代码要可以运行在任何一个有浏览器的设备上. 一台笔记本电脑:不需要花费很多钱得那种,只要它可以运行 ...

  10. 【我的Android进阶之旅】解决AndroidStudio编译时报错:Timeout waiting to lock artifact cache .

    1. 错误描述 今天在Android Studio中,使用gradle命令的时候,出现了如下所示的错误: D:\GitLab Source\XTCLint>gradlew clean uploa ...