[bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT
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
1
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
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。之后的操作类似。
Source
Solution
码农题
看见只有合并和查询k大不难想到主席树+启发式合并,但是这题还要动态维护lca,所以还要写个lct。
合并的时候,因为要新加入一个点的权值(小的接到大的的根上,成为大的的直系儿子,所以要加上大的根的权值),所以小的部分整个要dfs一波来更新,启发式合并可以做到\(O(nlog^2n)\)。
对于动态维护lca,很显然能用lct维护,不过细节比较多,要注意pushdown的顺序以及时机,还有就是找lca就是access(x)之后在access(y)时,找到的最后一个拼接点。找lca的fa时,就在splay里面按照平衡树的排序方式找即可。
Code
#include <bits/stdc++.h>
using namespace std;
#define N 80005
//fastIO
namespace IO
{
const int __S=(1<<21)+5;char __buf[__S],*__H,*__T;
inline char getc()
{
if(__H==__T) __T=(__H=__buf)+fread(__buf,1,__S,stdin);
if(__H==__T) return -1;return *__H++;
}
template <class __I>inline void read(__I &__x)
{
__x=0;char __c=getc();
while(!isdigit(__c)) __c=getc();
while(isdigit(__c)) __x=__x*10+__c-'0',__c=getc();
}
inline void readd(double &__x)
{
__x=0;double __fg=1.0;char __c=getc();
while(!isdigit(__c)&&__c!='-') __c=getc();
if(__c=='-') __fg=-1.0,__c=getc();
while(isdigit(__c)) __x=__x*10.0+__c-'0',__c=getc();
if(__c!='.'){__x=__x*__fg;return;}else while(!isdigit(__c)) __c=getc();
double __t=1e-1;while(isdigit(__c)) __x=__x+1.0*(__c-'0')*__t,__t=__t*0.1,__c=getc();
__x=__x*__fg;
}
inline void reads(char *__s,int __x)
{
char __c=getc();int __tot=__x-1;
while(__c<'!'||__c>'~') __c=getc();
while(__c>='!'&&__c<='~') __s[++__tot]=__c,__c=getc();
__s[++__tot]='\0';
}
char __obuf[__S],*__oS=__obuf,*__oT=__oS+__S-1,__c,__qu[55];int __qr;
inline void flush(){fwrite(__obuf,1,__oS-__obuf,stdout);__oS=__obuf;}
inline void putc(char __x){*__oS++ =__x;if(__oS==__oT) flush();}
template <class __I>inline void print(__I __x)
{
if(!__x) putc('0');
if(__x<0) putc('-'),__x=-__x;
while(__x) __qu[++__qr]=__x%10+'0',__x/=10;
while(__qr) putc(__qu[__qr--]);
}
inline void prints(const char *__s,const int __x)
{
int __len=strlen(__s+__x);
for(int __i=__x;__i<__len+__x;__i++) putc(__s[__i]);
}
inline void printd(double __x,int __d)
{
long long __t=(long long)floor(__x);print(__t);putc('.');__x-=(double)__t;
while(__d--)
{
double __y=__x*10.0;__x*=10.0;
int __c=(int)floor(__y);
putc(__c+'0');__x-=floor(__y);
}
}
inline void el(){putc('\n');}inline void sp(){putc(' ');}
}using namespace IO;
//value
int T,n,m,q,tot,x,y,z,la,cnt,lim;
int a[N*2],b[N*2],rt[N*2],sm[N*400],ls[N*400],rs[N*400],fa[N*2],f[N*2],c[N*2][2],re[N*2],to[N*2*2],he[N*2],ne[N*2*2],sz[N*2];
char o[5];
//basis
void add(int x,int y){to[cnt]=y;ne[cnt]=he[x];he[x]=cnt++;}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
//lct
bool isrt(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
bool R(int x,int y){return c[x][1]==y;}
void dn(int x){if(!re[x]) return;re[x]^=1;re[c[x][0]]^=1;re[c[x][1]]^=1;swap(c[x][0],c[x][1]);}
void ro(int x)
{
int y=fa[x],z=fa[y],a=R(y,x),b=!a;if(!isrt(y)) c[z][R(z,y)]=x;
fa[x]=z,fa[y]=x,fa[c[x][b]]=y;c[y][a]=c[x][b],c[x][b]=y;
}
void U(int x){if(fa[x]) U(fa[x]);dn(x);}
void spl(int x){U(x);for(;!isrt(x);ro(x)) if(!isrt(fa[x])) ro(R(fa[x],x)==R(fa[fa[x]],fa[x])?fa[x]:x);}
int acs(int x){int g;for(int y=0;x;y=x,x=fa[x]) spl(x),c[x][1]=y,g=x;return g;}
void mrt(int x){acs(x);spl(x);re[x]^=1;}
void lnk(int x,int y){mrt(x);fa[x]=y;}
int lca(int x,int y){acs(x);return acs(y);}
//segment
void ins(int &y,int x,int l,int r,int v)
{
y=++tot;sm[y]=sm[x]+1;if(l==r) return;int mid=(l+r)>>1;
if(v<=mid) rs[y]=rs[x],ins(ls[y],ls[x],l,mid,v);else ls[y]=ls[x],ins(rs[y],rs[x],mid+1,r,v);
}
int que(int a,int b,int c,int d,int l,int r,int k)
{
if(l==r) return l;int mid=(l+r)>>1,g=sm[ls[a]]+sm[ls[b]]-sm[ls[c]]-sm[ls[d]];
return k<=g?que(ls[a],ls[b],ls[c],ls[d],l,mid,k):que(rs[a],rs[b],rs[c],rs[d],mid+1,r,k-g);
}
//merge
void dfs(int x,int fa)
{
ins(rt[x],rt[fa],1,lim,a[x]);
for(int i=he[x],y;~i;i=ne[i]) if((y=to[i])!=fa) dfs(y,x);
}
void merge(int x,int y)
{
if(sz[x]<sz[y]) swap(x,y);int a=find(x),b=find(y);
sz[a]+=sz[b];f[b]=a;add(x,y);add(y,x);lnk(x,y);
}
//main
int main()
{
memset(he,-1,sizeof(he));read(T);read(n);read(m);read(q);
for(int i=1;i<=n;i++) read(a[i]),f[i]=i,sz[i]=1,b[i]=a[i];
sort(b+1,b+n+1);lim=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+n+1,a[i])-b;
for(int i=1;i<=n;i++) ins(rt[i],rt[0],1,lim,a[i]);
for(int i=1;i<=m;i++) read(x),read(y),merge(x,y);
for(int i=1;i<=q;i++)
{
reads(o,0);
if(o[0]=='L') read(x),read(y),x^=la,y^=la,merge(x,y);
else
{
read(x),read(y),read(z);x^=la,y^=la,z^=la;mrt(find(x));
int Lc=lca(x,y),Fa;acs(Lc);spl(Lc);Fa=c[Lc][0];
dn(Fa);while(c[Fa][1]) Fa=c[Fa][1],dn(Fa);
print(la=b[que(rt[x],rt[y],rt[Lc],rt[Fa],1,lim,z)]),el();
}
}
flush();
}
[bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT的更多相关文章
- [BZOJ3123][Sdoi2013]森林 主席树+启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当 ...
- 【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 ...
随机推荐
- ffmpeg源码分析--av_find_best_stream <转>
1. av_find_best_streama. 就是要获取音视频及字幕的stream_indexb.以前没有函数av_find_best_stream时,获取索引可以通过如下 ; i<is-& ...
- 在浏览器输入URL后发生了什么?
摘录部分一:https://www.cnblogs.com/kongxy/p/4615226.html 从输入URL到浏览器显示页面发生了什么 当在浏览器地址栏输入网址,如:www.baidu.com ...
- VUE项目 - IE报vuex requires a Promise polyfill in this browser问题解决
第一步: 安装 babel-polyfill . babel-polyfill可以模拟ES6使用的环境,可以使用ES6的所有新方法 npm install --save babel-polyfill ...
- tr th td
<table> <caption></caption> <thead> <tr> & ...
- Notepad++中的高级查找
准备以下字符串用来演示 abcdeab cdeabcde abcd eabcde 基于扩展的查找 基于扩展的查找不能算是真正的正则表达式搜索,因此这种查找方式仅是提供了支持转义字符.主要常用的 ...
- eShopOnContainer 第一步
运行结果截图: 操作流程: 1. git上clone 项目 windows版的docker并且安装成功,配置3核CPU,4G内存 vs 2017 (15.5)版本以上. 打开项目 eshopOnCon ...
- Redis AOF文件
[Redis AOF文件] 1.关于AOF AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集. AOF 文件中的命令全部以 Redis 协议的格式来保存 ...
- iOS对HTTPS证书链的验证原理
今天看到所在的某个开发群问https原理,之前做HTTPS ,下面简单说下原理.希望能帮助你理解. HTTPS从最终的数据解析的角度,与HTTP相同.HTTPS将HTTP协议数据包放到SSL/TSL层 ...
- jQuery的选择器的总结
一.简单选择器 // $(function () { // $("#box").css("color","red") // }) // 这个 ...
- Golang之文件读写
读写文件,不添加文件路径,默认写入到GOPATH路径下 终端读写: 源码 func Sscanf func Sscanf(str string, format string, a ...interfa ...