题意:一个带点权的森林,要求维护以下操作:

1.询问路径上的点权K大值

2.两点之间连边

n,m<=80000

思路:如果树的结构不发生变化只需要维护DFS序

现在因为树的结构发生变化,要将两棵树合并,这步可以用启发式合并,将比较小的树暴力连接到较大的树上面

离线的LCA算法无法维护,而倍增可以合并,所以用倍增求LCA

其余就是主席树,维护根到点的权值线段树就行了

机房里的罗爷爷写法比我高到不知道哪里去了

 #include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=;
int cas,n,m,q,i,x,y,k,edgenum,cnt,ans;
int a[M],b[M],c[M],head[M],vet[M],next[M],dep[M],fa[M][],f[M],size[M],root[M];
struct node{int l,r,w;}tree[M*];
bool cmp(int x,int y){return a[x]<a[y];}
int search(int x){
if (f[x]!=x)f[x]=search(f[x]);
return f[x];
}
void addedge(int x,int y){
vet[++edgenum]=y;
next[edgenum]=head[x];
head[x]=edgenum;
}
void update(int x,int l,int r,int &p){
tree[++cnt]=tree[p];p=cnt;tree[p].w++;
if (l==r)return;
int mid=l+r>>;
if (x<=mid)update(x,l,mid,tree[p].l);
else update(x,mid+,r,tree[p].r);
}
int query(int l,int r,int k,int x,int y,int z,int w){
if (l==r)return l;
int mid=l+r>>,t=tree[tree[x].l].w+tree[tree[y].l].w-tree[tree[z].l].w-tree[tree[w].l].w;
if (t>=k)return query(l,mid,k,tree[x].l,tree[y].l,tree[z].l,tree[w].l);
else return query(mid+,r,k-t,tree[x].r,tree[y].r,tree[z].r,tree[w].r);
}
int lca(int x,int y){
if (dep[x]<dep[y])swap(x,y);
int t=dep[x]-dep[y];
for (int i=;i<=;i++)
if (t&(<<i))x=fa[x][i];
for (int i=;i>=;i--)
if (fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
if (x==y)return x;
return fa[x][];
}
void dfs(int u,int pre){
fa[u][]=pre;
for (int i=;i<=;i++)fa[u][i]=fa[fa[u][i-]][i-];
root[u]=root[pre];
update(c[u],,n,root[u]);
for (int e=head[u];e;e=next[e]){
int v=vet[e];
if (v==pre)continue;
dep[v]=dep[u]+;
dfs(v,u);
}
}
void link(int x,int y){
int p=search(x),q=search(y);
if (size[p]>size[q]){swap(x,y);swap(p,q);}
dep[x]=dep[y]+;
dfs(x,y);
f[p]=q;size[q]+=size[p];
addedge(x,y);
addedge(y,x);
}
int main(){
scanf("%d",&cas);
scanf("%d%d%d",&n,&m,&q);
for (i=;i<=n;i++)scanf("%d",&a[i]),b[i]=i;
sort(b+,b+n+,cmp);
for (i=;i<=n;i++)c[b[i]]=i;
for (i=;i<=n;i++)f[i]=i,size[i]=;
cnt=n;
for (i=;i<=n;i++)root[i]=i,update(c[i],,n,root[i]);
for (i=;i<=m;i++){
scanf("%d%d",&x,&y);
link(x,y);
}
while (q--){
char s[];
scanf("%s",s);
if (s[]=='L'){
scanf("%d%d",&x,&y);
x^=ans;y^=ans;
link(x,y);
}else{
scanf("%d%d%d",&x,&y,&k);
x^=ans;y^=ans;k^=ans;
int z=lca(x,y);
printf("%d\n",ans=a[b[query(,n,k,root[x],root[y],root[z],root[fa[z][]])]]);
}
}
}

这是我的萎靡写法

 var t:array[..]of record
l,r,s:longint;
end;
f:array[..,..]of longint;
root,head,c,a,hash,h,dep,stk,size:array[..]of longint;
vet,next:array[..]of longint;
n,m,x,y,z,lastans,i,j,tot,cnt,k,s,up,top,que:longint;
ch:string; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
i:=l; j:=r; mid:=c[(l+r)>>];
repeat
while mid>c[i] do inc(i);
while mid<c[j] do dec(j);
if i<=j then
begin
swap(c[i],c[j]);
inc(i); dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end; function lsh(x:longint):longint;
var l,r,mid:longint;
begin
l:=; r:=up;
while l<=r do
begin
mid:=(l+r)>>;
if x=hash[mid] then exit(mid);
if x<hash[mid] then r:=mid-
else l:=mid+;
end;
end; function find(k:longint):longint;
begin
if h[k]<>k then h[k]:=find(h[k]);
exit(h[k]);
end; procedure add(a,b:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
head[a]:=tot;
end; procedure pushup(p:longint);
begin
t[p].s:=t[t[p].l].s+t[t[p].r].s;
end; procedure update(l,r,x:longint;var y:longint;v:longint);
var mid:longint;
begin
inc(cnt); y:=cnt;
t[y]:=t[x]; inc(t[y].s);
if l=r then exit;
mid:=(l+r)>>;
if v<=mid then update(l,mid,t[x].l,t[y].l,v)
else update(mid+,r,t[x].r,t[y].r,v);
pushup(y);
end; procedure dfs(u,pre:longint);
var e,v,x,y:longint;
begin
update(,up,root[pre],root[u],a[u]);
e:=head[u];
dep[u]:=dep[pre]+;
f[u,]:=pre;
while e<> do
begin
v:=vet[e];
if v<>pre then
begin
dfs(v,u);
x:=find(v); y:=find(u);
if size[x]<size[y] then
begin
size[x]:=size[y]+size[x];
h[y]:=x;
end
else begin size[y]:=size[x]+size[y]; h[x]:=y; end;
end;
e:=next[e];
end;
end; function lca(x,y:longint):longint;
var i,d:longint;
begin
if dep[x]<dep[y] then swap(x,y);
d:=dep[x]-dep[y];
for i:= to do
if d and (<<i)> then x:=f[x,i];
for i:= downto do
if f[x,i]<>f[y,i] then
begin
x:=f[x,i]; y:=f[y,i];
end;
if x=y then exit(x);
exit(f[x,]);
end; function query(l,r,x,y,z,w,k:longint):longint;
var mid,tmp:longint;
begin
if l=r then exit(l);
mid:=(l+r)>>;
tmp:=t[t[x].l].s+t[t[y].l].s-t[t[z].l].s-t[t[w].l].s;
if tmp>=k then
begin
x:=t[x].l; y:=t[y].l; z:=t[z].l; w:=t[w].l;
exit(query(l,mid,x,y,z,w,k));
end
else
begin
x:=t[x].r; y:=t[y].r; z:=t[z].r; w:=t[w].r;
exit(query(mid+,r,x,y,z,w,k-tmp));
end;
end; function ask(x,y,z:longint):longint;
var q:longint;
begin
q:=lca(x,y);
exit(hash[query(,up,root[x],root[y],root[q],root[f[q,]],z)]);
end; procedure rebuild(u,pre:longint);
var e,v:longint;
begin
inc(top); stk[top]:=u;
update(,up,root[pre],root[u],a[u]);
dep[u]:=dep[pre]+;
f[u,]:=pre;
e:=head[u];
while e<> do
begin
v:=vet[e];
if v<>pre then rebuild(v,u);
e:=next[e];
end;
end; procedure merge(x,y:longint);
var tx,ty,z,i,j:longint;
begin
tx:=find(x); ty:=find(y);
if size[tx]>size[ty] then
begin
swap(tx,ty); swap(x,y);
end;
top:=;
add(x,y); add(y,x);
rebuild(x,y);
h[tx]:=ty; size[ty]:=size[ty]+size[tx];
for i:= to do
for j:= to top do
begin
z:=stk[j];
f[z,i]:=f[f[z,i-],i-];
end;
end; begin
assign(input,'bzoj3123.in'); reset(input);
assign(output,'bzoj3123.out'); rewrite(output);
readln(x);
readln(n,m,que);
for i:= to n do
begin
read(a[i]);
c[i]:=a[i];
end;
qsort(,n);
up:=; hash[]:=c[];
for i:= to n do
if c[i]<>c[i-] then begin inc(up); hash[up]:=c[i]; end;
for i:= to n do a[i]:=lsh(a[i]);
for i:= to m do
begin
readln(x,y);
add(x,y);
add(y,x);
end;
for i:= to n do
begin
h[i]:=i; size[i]:=;
end;
for i:= to n do
if root[i]= then dfs(i,);
for i:= to do
for j:= to n do f[j,i]:=f[f[j,i-],i-];
for i:= to que do
begin
readln(ch); s:=; k:=length(ch); x:=; y:=; z:=;
for j:= to k do
begin
if ch[j]=' ' then begin if ch[j-]<>' ' then inc(s); continue; end;
if s= then x:=x*+ord(ch[j])-ord('');
if s= then y:=y*+ord(ch[j])-ord('');
if s= then z:=z*+ord(ch[j])-ord('');
end;
if ch[]='Q' then
begin
x:=x xor lastans; y:=y xor lastans; z:=z xor lastans; //writeln(x,' ',y,' ',z);
k:=ask(x,y,z);
writeln(k);
lastans:=k;
end
else
begin
x:=x xor lastans; y:=y xor lastans;// writeln(x,' ',y,' ',z);
merge(x,y);
end; end;
close(input);
close(output);
end.

【BZOJ3123】森林(主席树,启发式合并)的更多相关文章

  1. 【BZOJ-3123】森林 主席树 + 启发式合并

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

  2. [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT

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

  3. Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)

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

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

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

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

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

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

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

  7. [SDOI2013]森林 主席树+启发式合并

    这题的想法真的很妙啊. 看到题的第一眼,我先想到树链剖分,并把\(DFS\)序当成一段区间上主席树.但是会发现在询问的时候,可能会非常复杂,因为你需要把路径拆成很多条轻链和重链,它们还不一定连续,很难 ...

  8. 【BZOJ 3123】 [Sdoi2013]森林 主席树启发式合并

    我们直接按父子关系建主席树,然后记录倍增方便以后求LCA,同时用并查集维护根节点,而且还要记录根节点对应的size,用来对其启发式合并,然后每当我们合并的时候我们都要暴力拆小的一部分重复以上部分,总时 ...

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

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

  10. 【主席树 启发式合并】bzoj3123: [Sdoi2013]森林

    小细节磕磕碰碰浪费了半个多小时的时间 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M ...

随机推荐

  1. 01-C#入门(调试和错误处理)

    老实说,这一章没有什么要写的,很多都是实操性的东西. 调试方法 可以使用Debug.WriteLine().Trace.WriteLine()输入调试信息到窗体下的输出窗口,不过没怎么用过,比较有用的 ...

  2. 一些常用的sql语句

    1.查询表里的null值:is null 和 is not null  select*from student where email is null       返回的该表里面邮箱为null的结果集 ...

  3. SparkSQL DataFrames操作

    Hive中已经存在emp和dept表: select * from emp; +--------+---------+------------+-------+-------------+------ ...

  4. OpenGL学习笔记2——顶点数组

    #pragma comment(lib,"glut32.lib") #pragma comment(lib,"glut.lib") #pragma commen ...

  5. win7双系统安装ubuntu并配置常用软件

    首先在win7下磁盘清理出来空间具体方法找度娘就行了. 下面开始准备安装: 1.下载easyBCD 2.打开:添加新条目--NeoGub--安装 3.点击配置  修改menu.lst title In ...

  6. autoit 将输入法修改为英文输入法

    如果能用ControlSend,就不推荐用send,如果非要用send,可以切换输入法为英文再send. $hWnd = WinGetHandle("[ACTIVE]");$hWn ...

  7. win7远程桌面恢复全屏状态快捷键

    不同的电脑可能有不同的快捷键(有些笔记本电脑甚至没有相应的键值):①台式机:ctrl+alt+break 组合键.②CTRL+ALT+PAGEDOWN 组合键.③有的笔记本没有break键,可以尝试加 ...

  8. Hive修改表

    Alter Table 语句 它是在Hive中用来修改的表. 语法 声明接受任意属性,我们希望在一个表中修改以下语法. ALTER TABLE name RENAME TO new_name ALTE ...

  9. DVD管理器集合版

    利用所学的集合写出的DVD管理系统,运用到了所学到集合基础. import java.text.ParseException; import java.text.SimpleDateFormat; i ...

  10. kettle之mongodb数据同步

    需求: 1.源数据库新增一条记录,目标库同时新增一条记录: 2.源数据库修改一条记录,目标库同时修改该条记录: 示例用到三个Kettle组件 下面详细说下每个组件的配置 Source: 本示例连接的是 ...