http://www.lydsy.com/JudgeOnline/problem.php?id=3123 (题目链接)

题意

  给出$n$个点的森林,每个点有一个非负点权,$m$个操作。连接两个点,查询两个点之间路径上的第$K$大点权。强制在线。

Solution

  主席树+启发式合并。

  对于查询操作,主席树维护区间第$K$大即可,当前节点新建的节点是在其父亲节点基础上建立的,也就是说这个主席树维护的是到根的路径。

  对于连接操作,直接启发式合并暴力搞过去就可以了,记得同时更新$size$和$fa$以及重建主席树。

细节

  原来不是多组数据,只是当前数据对应的是数据范围的第几个部分分,好良心的主题人啊→_→

  果然using namespace 就清晰很多,调过样例就直接过了。

代码

// bzoj3123
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define lim 1000000000
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std; const int maxn=100010;
int Dargen[maxn],size[maxn],deep[maxn],head[maxn],fa[maxn][30],bin[30];
int n,m,Q,sz,ans,cnt,a[maxn],rt[maxn];
struct edge {int to,next;}e[maxn<<1];
struct node {
int son[2],s;
void clear() {son[0]=son[1]=0;s=0;}
int& operator [] (int x) {return son[x];}
}tr[maxn*40]; namespace Chairtree {
void build(int &u,int v,int l,int r,int val) {
if (!u) u=++sz;
if (l==r) {tr[u].s=tr[v].s+1;return;}
int mid=(l+r)>>1;
if (val<=mid) build(tr[u][0],tr[v][0],l,mid,val),tr[u][1]=tr[v][1];
else build(tr[u][1],tr[v][1],mid+1,r,val),tr[u][0]=tr[v][0];
tr[u].s=tr[tr[u][0]].s+tr[tr[u][1]].s;
}
void merge(int x,int y) {
build(rt[x],rt[y],0,lim,a[x]);
Dargen[x]=Dargen[y];fa[x][0]=y;
deep[x]=deep[y]+1;
for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
merge(e[i].to,x);
size[x]+=size[e[i].to];
}
}
int query(int u,int v,int w,int x,int l,int r,int K) {
if (l==r) return l;
int mid=(l+r)>>1,c=tr[tr[u][0]].s+tr[tr[v][0]].s-tr[tr[w][0]].s-tr[tr[x][0]].s;
if (c>=K) return query(tr[u][0],tr[v][0],tr[w][0],tr[x][0],l,mid,K);
else return query(tr[u][1],tr[v][1],tr[w][1],tr[x][1],mid+1,r,K-c);
}
}
using namespace Chairtree; namespace Tree {
void link(int u,int v) {
e[++cnt]=(edge){v,head[u]};head[u]=cnt;
e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
void dfs(int x) {
size[x]=1;build(rt[x],rt[fa[x][0]],0,lim,a[x]);
Dargen[x]=fa[x][0] ? Dargen[fa[x][0]] : x;
for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
fa[e[i].to][0]=x;
deep[e[i].to]=deep[x]+1;
dfs(e[i].to);
size[x]+=size[e[i].to];
}
}
int lca(int x,int y) {
if (deep[x]<deep[y]) swap(x,y);
int t=deep[x]-deep[y];
for (int i=0;bin[i]<=t;i++) if (bin[i]&t) x=fa[x][i];
for (int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return x==y ? x : fa[x][0];
}
}
using namespace Tree; int main() {
char ch[10];int T;scanf("%d",&T);
bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
scanf("%d%d%d",&n,&m,&Q);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int u,v,i=1;i<=m;i++) {
scanf("%d%d",&u,&v);
link(u,v);
}
for (int i=1;i<=n;i++) if (!size[i]) dfs(i);
for (int x,y,K,i=1;i<=Q;i++) {
scanf("%s%d%d",ch,&x,&y);
x^=ans,y^=ans;
if (ch[0]=='L') {
link(x,y);
if (size[Dargen[x]]>size[Dargen[y]]) swap(x,y);
size[Dargen[y]]+=size[Dargen[x]];
merge(x,y);
}
if (ch[0]=='Q') {
scanf("%d",&K);
K^=ans;
int f=lca(x,y);
ans=query(rt[x],rt[y],rt[f],rt[fa[f][0]],0,lim,K);
printf("%d\n",ans);
}
}
return 0;
}

【bzoj3132】 Sdoi2013—森林的更多相关文章

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

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

  2. luoguP3302 [SDOI2013]森林 主席树 启发式合并

    题目链接 luoguP3302 [SDOI2013]森林 题解 本来这题树上主席树暴力启发式合并就完了 结果把lca写错了... 以后再也不这么写了 复杂度\(O(nlog^2n)\) "f ...

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

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

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

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

  5. BZOJ3123: [Sdoi2013]森林(启发式合并&主席树)

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

  6. 【BZOJ3123】[Sdoi2013]森林 主席树+倍增LCA+启发式合并

    [BZOJ3123][Sdoi2013]森林 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整 ...

  7. 洛谷 P3302 [SDOI2013]森林 解题报告

    P3302 [SDOI2013]森林 题目描述 小\(Z\)有一片森林,含有\(N\)个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有\(M\)条边. 小Z希望执行\(T\)个操作,操 ...

  8. 3123: [Sdoi2013]森林

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

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

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

  10. AC日记——[Sdoi2013]森林 bzoj 3123

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

随机推荐

  1. test_maven_实现表单验证

    这篇文章是我的上一篇文章的续集,如未看过,可看一下,上面的test_maven再继续看这个 这篇文章主要是阐述使用struts实现表单验证的功能. 1.首先了解actionContext:Action ...

  2. XSS Challenges练习及解答

    一个偶然的机会在知道创宇的技能表里看到了一个练习XSS的网站http://xss-quiz.int21h.jp,正好想研究这个,于是试着做了一下. 第一.二题是最简单的,直接在搜索框中输入以下代码就成 ...

  3. 20155308《网络攻防》 Exp1 PC平台逆向破解(5)M

    20155308<网络攻防> Exp1 PC平台逆向破解(5)M 逆向及Bof基础实践说明 1.1 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是 ...

  4. 20155321 《网络攻防》 Exp2 后门原理与实践

    20155321 <网络攻防> Exp2 后门原理与实践 实验内容 例举你能想到的一个后门进入到你系统中的可能方式? 我觉得人们在平时上网的时候可能会无意识地点击到一些恶意的网站,这些网站 ...

  5. Java实现Zip压缩包解压

        对zip压缩包的解压是比较常见的应用场景,java代码的实现也很简单.废话不多说,直接上代码吧 一.代码 /** * zip解压 * @param srcFile zip源文件 * @para ...

  6. sprintboot 和swagger2整合生成文档

    1.创建springboot 工程 2.引入maven依赖 <dependency> <groupId>io.springfox</groupId> <art ...

  7. HW 2017 12 17可禾大佬神题

    好不容易搞来的题目,不写一写怎么行呢. 不过难度真心不高(一小时K掉),都是老题+暴力题,没有欧洲玄学. 再说一句,这试卷是叶可禾出的吧. T1 好老的题目,看到有多组数据我还怕了,以为有更流弊的算法 ...

  8. 记一次Java加密加签算法到php的坑

    此文为本人原创首发于 http://www.35coder.com/convert_encryption_codes_to_php/. 写代码的经历中,总少不了与外部的程序对接,一旦有这样的事,往往周 ...

  9. MIT 6.824 lab1:mapreduce

    这是 MIT 6.824 课程 lab1 的学习总结,记录我在学习过程中的收获和踩的坑. 我的实验环境是 windows 10,所以对lab的code 做了一些环境上的修改,如果你仅仅对code 感兴 ...

  10. 20135202闫佳歆--week3 跟踪分析Linux内核的启动过程--实验及总结

    实验三:跟踪分析Linux内核的启动过程 一.调试步骤如下: 使用gdb跟踪调试内核 qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd r ...