[bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)
Description
.jpg)
Input
第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。
Output
对于每一个第一类操作,输出一个非负整数表示答案。
Sample Input
Q Q
Q
L
L L
Q Q
Sample Output
HINT
对于第一个操作 Q 8 7 3,此时 lastans=0,所以真实操作为Q 8^0 7^0 3^0,也即Q 8 7 3。点8到点7的路径上一共有5个点,其权值为4 1 1 2 4。这些权值中,第三小的为 2,输出 2,lastans变为2。对于第二个操作 Q 3 5 1 ,此时lastans=2,所以真实操作为Q 3^2 5^2 1^2 ,也即Q 1 7 3。点1到点7的路径上一共有4个点,其权值为 1 1 2 4 。这些权值中,第三小的为2,输出2,lastans变为 2。之后的操作类似。
.jpg)
Solution
时限比较长暗示此题的解法比较暴力
和前面count on a tree的做法一样,先遍历整片森林,初始化倍增数组,把点投到可持久化线段树里去
对于询问操作,一样地,直接递归求解即可
对于连接操作,我们用并查集加size域启发式合并来处理森林的联通状况,方便我们重构树的时候减少重构的点的数量,这样就优化了暴力重构的时间
#include<stdio.h>
#include<string.h>
#define N 80110
#define INF 1000000000
#define mid ((x>>1)+(y>>1)+(x&y&1))
inline void exc(int &x,int &y){
x^=y;y^=x;x^=y;
}
inline int Rin(){
int x=,c=getchar(),f=;
for(;c<||c>;c=getchar())
if(!(c^))f=-;
for(;c>&&c<;c=getchar())
x=(x<<)+(x<<)+c-;
return x*f;
}
int n,m,T,val[N],jump[N][],dep[N],pb[N],top,ans;
struct st{int f,s;}s[N];
inline int pre(int x){
while(s[x].f^x)x=s[x].f;
return x;
}
inline void onion(int x,int y){
x=pre(x),y=pre(y);
s[y].f=x,s[x].s+=s[y].s;
}
struct pt{int v;pt *nxt;}
*fst[N],e[N<<],*tot=e;
inline void link(int x,int y){
*++tot=(pt){y,fst[x]},fst[x]=tot;
*++tot=(pt){x,fst[y]},fst[y]=tot;
}
struct nt{
nt *l,*r;
int s;
}*rt[N],pool[],*C=pool;
inline nt *newnt(nt *_,nt *__,int ___){
C->l=_;C->r=__;C->s=___;
return C++;
}
nt *build(nt *p,int x,int y,int k){
if(!(x^y))return newnt(0x0,0x0,p->s+);
if(k<=mid)return newnt(build(p->l,x,mid,k),p->r,p->s+);
return newnt(p->l,build(p->r,mid+,y,k),p->s+);
}
void dfs(int x){
dep[x]=dep[jump[x][]]+;
rt[x]=build(rt[jump[x][]],,INF,val[x]);
for(pt *j=fst[x];j;j=j->nxt)
if(j->v^jump[x][])
jump[j->v][]=x,
dfs(j->v);
}
void dfs(int x,int f){
pb[++top]=x;
jump[x][]=f;
dep[x]=dep[f]+;
rt[x]=build(rt[f],,INF,val[x]);
for(pt *j=fst[x];j;j=j->nxt)
if(j->v^f)dfs(j->v,x);
}
int lca(int x,int y){
if(dep[x]<dep[y])exc(x,y);
for(int j=;~j;j--)
if(dep[jump[x][j]]>=dep[y])
x=jump[x][j];
if(!(x^y))return x;
for(int j=;~j;j--)
if(jump[x][j]^jump[y][j])
x=jump[x][j],y=jump[y][j];
return jump[x][];
}
int secret(nt *p1,nt *p2,nt *p3,nt *p4,int x,int y,int k){
if(!(x^y))return x;
int c=p1->l->s+p2->l->s-p3->l->s-p4->l->s;
if(k<=c)return secret(p1->l,p2->l,p3->l,p4->l,x,mid,k);
return secret(p1->r,p2->r,p3->r,p4->r,mid+,y,k-c);
}
int feel(int x,int y,int k){
int t=lca(x,y);
return secret(rt[x],rt[y],rt[t],rt[jump[t][]],,INF,k);
}
int main(){
T=Rin(),n=Rin(),m=Rin(),T=Rin();
for(int i=;i<=n;i++)
s[i].f=i,s[i].s=;
for(int i=;i<=n;i++)
val[i]=Rin();
for(int x,y;m;m--)
x=Rin(),y=Rin(),link(x,y),onion(x,y);
rt[]=newnt(C,C,);
for(int i=;i<=n;i++)
if(!jump[i][])
dfs(i);
for(int j=;j<=;j++)
for(int i=;i<=n;i++)
jump[i][j]=jump[jump[i][j-]][j-];
char sign[];
for(int x,y,k;T;T--){
scanf("%s",sign);
x=Rin()^ans,y=Rin()^ans;
if(sign[]=='Q'){
k=Rin()^ans;
printf("%d\n",ans=feel(x,y,k));
}
else{
if(s[pre(x)].s>s[pre(y)].s)
exc(x,y);
top=;
dfs(x,y);
onion(x,y);
for(int j=;j<=;j++)
for(int i=;i<=top;i++)
jump[pb[i]][j]=jump[jump[pb[i]][j-]][j-];
link(x,y);
}
}
return ;
}
[bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)的更多相关文章
- 洛谷P3402 【模板】可持久化并查集 [主席树,并查集]
题目传送门 可持久化并查集 n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 ...
- BZOJ2733[HNOI2012]永无乡——线段树合并+并查集+启发式合并
题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...
- bzoj3123 [Sdoi2013]森林 树上主席树+启发式合并
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3123 题解 如果是静态的查询操作,那么就是直接树上主席树的板子. 但是我们现在有了一个连接两棵 ...
- SPOJ COT Count on a tree(树上主席树 + LCA 求点第k小)题解
题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点 ...
- [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)
[BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...
- 并查集+启发式合并+LCA思想 || 冷战 || BZOJ 4668
题面:bzoj炸了,以后再补发 题解: 并查集,然后对于每个点记录它与父亲节点联通的时刻 tim ,答案显然是 u 到 v 的路径上最大的 tim 值.启发式合并,把 size 小的子树往大的上并,可 ...
- 2017 Multi-University Training Contest - Team 4 phone call(树+lca+并查集)
题解: (并查集处理往上跳的时候,一定要先让u,v往上跳到并查集的祖先,不然会wa掉) 代码如下: #include <iostream> #include <algorithm&g ...
- bzoj 3123 [Sdoi2013]森林(主席树+启发式合并+LCA)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- p3302 [SDOI2013]森林(树上主席树+启发式合并)
对着题目yy了一天加上看了一中午题解,终于搞明白了我太弱了 连边就是合并线段树,把小的集合合并到大的上,可以保证规模至少增加一半,复杂度可以是\(O(logn)\) 合并的时候暴力dfs修改倍增数组和 ...
随机推荐
- 这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧
注意:有网友提出部分项目停止更新的事情,这个问题我特意注意过,很多都是小功能组件,功能稳定,没有bug,没更新是正常的.够用就行了.其次技术支持的事情,对开源免费来说,不能太强求,这里发布的都是小功能 ...
- C# 合并及拆分Word文档
本文简要分析一下如何如何使用C#简单实现合并和拆分word文档.平时我们在处理多个word文档时,可能会想要将两个文档合并为一个,或者是将某个文档的一部分添加到另一个文档中,有的时候也会想要将文档拆分 ...
- Oracle架构设计01:表空间的管理维护规范
Oracle数据库的表空间管理可以说是非常简单和基础的一项维护工作,但是越简单的事情就越要制定统一的规范,这样数据库的各项管理工作才会愈加的简单高效. 那么接下来,问题来了.. Q1:当我们接手一个新 ...
- 计算机网络学习笔记--数据链据层之MAC子层(整理)
概述: 为什么需要介质访问控制子层(MAC)? 介质访问控制子层(MAC)是局域网体系结构中划分的子层,多路访问链路采用共享介质连接所有站点.发送站点通过广播方式发送数据并占用整个带宽,如果有多个站点 ...
- [入门级] visual studio 2010 mvc4开发,用ibatis作为数据库访问媒介(一)
[入门级] visual studio 2010 mvc4开发,用ibatis作为数据库访问媒介(一) Date 周二 06 一月 2015 By 钟谢伟 Tags mvc4 / asp.net 示 ...
- SQL Server 统计信息更新时采样百分比对数据预估准确性的影响
为什么要写统计信息 最近看到园子里有人写统计信息,楼主也来凑热闹. 话说经常做数据库的,尤其是做开发的或者优化的,统计信息造成的性能问题应该说是司空见惯. 当然解决办法也并非一成不变,“一招鲜吃遍天” ...
- C# base 64图片编码解码
使用WinForm实现了图片base64编码解码的 效果图: 示例base 64编码字符串: /9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKD ...
- C#解决界面不响应
在我们的程序中,经常会有一些耗时较长的运算,为了保证用户体验,不引起界面不响应,我们一般会采用多线程操作,让耗时操作在后台完成,完成后再进行处理或给出提示,在运行中,也会时时去刷新界面上的进度条等显示 ...
- Redis命令拾遗一(字符串类型)
文章归博客园和作者“蜗牛”共同所有 .转载和爬虫请注明原文Redis系列链接 http://www.cnblogs.com/tdws/tag/NoSql/ Redis有五种基本数据类型.他们分别是字符 ...
- 在公有云AZURE上部署私有云AZUREPACK以及WEBSITE CLOUD(三)
(三) 搭建Windows Azure Pack环境 1安装SQL SERVER 2012 服务器 为简单起见,本例直接使用了Azure提供的具有SQLServer的Win2012 Server镜像来 ...