[BZOJ3123][Sdoi2013]森林 主席树+启发式合并
3123: [Sdoi2013]森林
Time Limit: 20 Sec Memory Limit: 512 MB
Description
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
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6
Sample Output
2
1
4
2
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。之后的操作类似。
题解:
看到求k值,我们很容易想到主席树这种求区间k大值的工具(不了解树上主席树的同学可以看一下我之前的讲解http://www.cnblogs.com/LadyLex/p/7275164.html,再参考一下下面的代码)
但是,本题的合并操作给我们带来了麻烦,让我们无处下手。难道我们之间暴力添加吗?肯定会T。
所以我们考虑利用启发式合并,即把个数较小的树插入个数较大的树中。
启发式合并的操作听起来和暴力没有什么区别,但是它的复杂度是有保障的:
每次合并,新树的大小是原来较小树大小的二倍以上,因此最多需要logn次合并成了1棵树。
每次合并平均是(n/2)log权值的,因此总时间复杂度是O(nlognlog权值)的
如果离散化的话,跑的就更快了,大约O(nlog2n)(不过我自己的代码没有离散,233)
代码见下:
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N=,MAXN=;
int n,cnt,val[N],sum,adj[N],e;
int origin[N],belong[N],size[N],deep[N];
struct edge{int zhong,next;}s[N<<];
inline void swap(int &a,int &b){int t=a;a=b;b=t;}
inline void add(int qi,int zhong){s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;}
int f[N][],bin[];
inline void mission1(int x)
{for(int i=;i<=;i++)f[x][i]=f[f[x][i-]][i-];}
inline int LCA(int a,int b)
{
if(deep[a]<deep[b])swap(a,b);
int cha=deep[a]-deep[b];
for(int j=;~j;j--)if(cha&bin[j])a=f[a][j];
if(a==b)return a;
for(int j=;~j;j--)
if(f[a][j]!=f[b][j])a=f[a][j],b=f[b][j];
return f[a][];
}
struct node
{
int cnt;node *ch[];
node(){cnt=;ch[]=ch[]=NULL;}
inline void update(){cnt=ch[]->cnt+ch[]->cnt;}
}*null=new node(),*root[N];
inline node* newnode()
{
node *o=new node();
o->ch[]=o->ch[]=null;
return o;
}
inline int query(int x,int y,int k)
{
int lca=LCA(x,y),t=f[lca][],l=,r=MAXN;
node *a=root[x],*b=root[y],*c=root[lca],*d=root[t];
while(l<r)
{
int tmp=a->ch[]->cnt+b->ch[]->cnt-c->ch[]->cnt-d->ch[]->cnt,mi=(l+r)>>;
if(tmp>=k)a=a->ch[],b=b->ch[],c=c->ch[],d=d->ch[],r=mi;
else k-=tmp,a=a->ch[],b=b->ch[],c=c->ch[],d=d->ch[],l=mi+;
}
return r;
}
void insert(node *&a,node *b,int l,int r,int pos)
{
a->cnt=b->cnt+;
int mi=(l+r)>>;
if(l==r)return;
if(pos<=mi)a->ch[]=b->ch[],a->ch[]=newnode(),insert(a->ch[],b->ch[],l,mi,pos);
else a->ch[]=b->ch[],a->ch[]=newnode(),insert(a->ch[],b->ch[],mi+,r,pos);
a->update();
}
void dfs1(int rt,int fa)
{
f[rt][]=fa;mission1(rt);
sum++;deep[rt]=deep[fa]+;belong[rt]=cnt;
insert(root[rt],root[fa],,MAXN,val[rt]);
for(int i=adj[rt];i;i=s[i].next)
if(s[i].zhong!=fa)dfs1(s[i].zhong,rt);
}
void dfs2(int rt,int fa,int anc)
{
f[rt][]=fa;deep[rt]=deep[fa]+;mission1(rt);belong[rt]=anc;
insert(root[rt],root[fa],,MAXN,val[rt]);
for(int i=adj[rt];i;i=s[i].next)
if(s[i].zhong!=fa)dfs2(s[i].zhong,rt,anc);
}
int main()
{
null->ch[]=null->ch[]=null;
bin[]=;for(int i=;i<=;i++)bin[i]=bin[i-]<<;
int ans=,m,t,a,b,d;char c[];scanf("%d",&t);
scanf("%d%d%d",&n,&m,&t);
for(int i=;i<=n;i++)root[i]=newnode();
for(int i=;i<=n;i++)scanf("%d",&val[i]);
while(m--)scanf("%d%d",&a,&b),add(a,b),add(b,a);
for(int i=;i<=n;i++)
if(!belong[i])sum=,cnt++,dfs1(i,),origin[cnt]=i,size[cnt]=sum;
while(t--)
{
scanf("%s%d%d",c,&a,&b);a^=ans,b^=ans;
if(c[]=='Q')scanf("%d",&d),d^=ans,printf("%d\n",ans=query(a,b,d));
else
{
add(a,b),add(b,a);
if(size[belong[a]]>size[belong[b]])
size[belong[a]]+=size[belong[b]],dfs2(b,a,belong[a]);
else size[belong[b]]+=size[belong[a]],dfs2(a,b,belong[b]);
}
}
}
[BZOJ3123][Sdoi2013]森林 主席树+启发式合并的更多相关文章
- [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- 【BZOJ-3123】森林 主席树 + 启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2738 Solved: 806[Submit][Status] ...
- Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...
- BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]
3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...
- luoguP3302 [SDOI2013]森林 主席树 启发式合并
题目链接 luoguP3302 [SDOI2013]森林 题解 本来这题树上主席树暴力启发式合并就完了 结果把lca写错了... 以后再也不这么写了 复杂度\(O(nlog^2n)\) "f ...
- [SDOI2013]森林 主席树+启发式合并
这题的想法真的很妙啊. 看到题的第一眼,我先想到树链剖分,并把\(DFS\)序当成一段区间上主席树.但是会发现在询问的时候,可能会非常复杂,因为你需要把路径拆成很多条轻链和重链,它们还不一定连续,很难 ...
- 【BZOJ 3123】 [Sdoi2013]森林 主席树启发式合并
我们直接按父子关系建主席树,然后记录倍增方便以后求LCA,同时用并查集维护根节点,而且还要记录根节点对应的size,用来对其启发式合并,然后每当我们合并的时候我们都要暴力拆小的一部分重复以上部分,总时 ...
- BZOJ3123[Sdoi2013]森林——主席树+LCA+启发式合并
题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...
- P3302 [SDOI2013]森林(主席树+启发式合并)
P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...
随机推荐
- react单页面应用的Nginx配置问题
项目中多数使用react单页面开发,路由使用react-router的browser-router,这样页面访问路径看起来像是真实的,如http://xx.xxx.xxx/a/b.但当项目访问路径为多 ...
- 容器监控—阿里云&容器内部服务监控
目前Docker的使用越来越离不开对容器的监控,阿里云最近上线了容器服务,不但提供了核心的容器和宿主机监控能力,而且支持集成 Cloud Insight 监控,下面会介绍如何集成. 首先介绍一下阿里云 ...
- 从零自学Java-7.使用数组存储信息
1.创建数组: 2.设置数组的大小: 3.为数组元素赋值: 4.修改数组中的信息: 5.创建多维数组: 6.数组排序. 程序SpaceRemover:显示输入字符串,并将其中所有的空格字符替换为句点字 ...
- 安卓ADB命令
查看连接的设备 adb devices -l FastBoot常用命令: fastboot erase system #擦除system分区 fastboot erase boot #擦除 ...
- Node.js+Ajax实现物流小工具
半年过去了,好像什么也没干,好像什么也干了. 最近在网易云课堂上看到了这个课程,觉得很有意思,就跟着课程做了一遍,课程地址:http://study.163.com/course/courseMain ...
- 减少MySQL的Sleep进程有效方法
经常遇到很多朋友问到,他的MySQL中有很多Sleep进程,严重占用MySQL的资源,现在分析一下出现这种现象的原因和解决办法: 1,通常来说,MySQL出现大量Sleep进程是因为采用的PHP的My ...
- USB 相关笔记
1分析已有代码项目 Android从USB声卡录制高质量音频-----使用libusb读取USB声卡数据 github 项目:usbaudio-android-demo usb声卡取数据项目也是参考的 ...
- python 函数闭包()
闭包(closure) 当一个函数在内部定义函数,并且内部的函数应用外部函数的参数或者局部变量,当内部函数被当做返回值的时候,相关参数和变量保存在返回函数中,这种结果,叫闭包 example1: de ...
- Linux 配置 hosts
1. hosts 是什么 维基百科对 hosts 的介绍如下: hosts文件(域名解析文件)是一个用于储存计算机网络中各节点信息的计算机文件. 这个文件负责将主机名称映射到相应的IP地址. host ...
- Skype 服务器客户端策略参数优化
1.skype通讯录原理 对于skype客户端的通讯录同步,首先说说原理,通讯簿信息是从AD同步的skype前端服务器(每天1:30),在从前端服务器同步的客户端(大概1小时内同步一次). skype ...