博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ 3123 森林 主席树启发式合并
阅读量:5267 次
发布时间:2019-06-14

本文共 3481 字,大约阅读时间需要 11 分钟。

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
如果这道题不带添加边的操作的话直接上主席树就可以了,那么现在加了边,主席树上树的朴素做法已经行不通了,那么考虑一下加了边实际上就是把两个联通分量连成了一个联通分量,那么我们就需要对两个联通分量所代表的主席树进行合并,那么为了保证时间复杂度,我们每次把size较小的联通分量合并到size较大的联通分量中去,并且把对应的主席树进行合并。然后就是朴素的主席树上树了。

#include 
#include
#include
const int MAXN = 100005;int first[MAXN],e=1,cnt,n,m,q,val[MAXN],id[MAXN],num,Hash[MAXN],sz;int belong[MAXN],fa[MAXN][25],size[MAXN],root[MAXN],Ans,deep[MAXN];bool vis[MAXN]; template
inline _t read(){ _t x=0,f=1; char ch=getchar(); for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f; for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+(ch^48); return x*f;} struct node{ int l,r,sum;}tree[20000005]; #define ls(x) tree[x].l#define rs(x) tree[x].r#define sum(x) tree[x].sum struct edge{ int u,v,next;}a[MAXN<<3]; void push(int u,int v){ a[e].u=u;a[e].v=v; a[e].next=first[u]; first[u]=e++;} void insert(int &o,int old,int l,int r,int x){ o=++cnt; tree[o]=tree[old]; sum(o)++; if(l==r)return; int m=l+r>>1; if(x<=m)insert(ls(o),ls(old),l,m,x); else insert(rs(o),rs(old),m+1,r,x); return;} inline void swap(int &x,int &y){x^=y;y^=x;x^=y;}inline void Hash_init(){std :: sort(&Hash[1],&Hash[n+1]);sz = std :: unique(&Hash[1],&Hash[n+1])-Hash-1;}inline int GHash(int x){return std :: lower_bound(&Hash[1],&Hash[sz+1],x)-Hash;} void build(int &o,int l,int r){ o=++cnt; sum(o)=0; if(l==r)return; int m=l+r>>1; build(ls(o),l,m); build(rs(o),m+1,r); return;} void dfs(int u,int f,int be){ size[u]=1; vis[u]=1;deep[u]=deep[f]+1; fa[u][0]=f;belong[u]=be; insert(root[u],root[f],1,sz,GHash(val[u])); for(int i=1;i<=19;i++) fa[u][i]=fa[fa[u][i-1]][i-1]; for(int i=first[u];i;i=a[i].next){ if(a[i].v==f)continue; dfs(a[i].v,u,be); size[u]+=size[a[i].v]; } return;} inline int lca(int x,int y){ if(deep[x]
=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0];} int Query(int u,int v,int k){ int x = lca(u,v),y=fa[x][0]; int l=1,r=sz; int root_u=root[u],root_v=root[v],root_lca=root[x],root_fa=root[y]; while(l
>1; if(tmp>=k){ root_u=tree[root_u].l;root_lca=tree[root_lca].l; root_v=tree[root_v].l;root_fa =tree[root_fa].l; r=m; } else{ k-=tmp; root_u=tree[root_u].r;root_lca=tree[root_lca].r; root_v=tree[root_v].r;root_fa =tree[root_fa].r; l=m+1; } } return Hash[l];} int main(){ read
(); n=read
();m=read
();q=read
(); for(int i=1;i<=n;i++)val[i]=read
(),Hash[i]=val[i]; for(int i=1;i<=m;i++){ int u=read
(),v=read
(); push(u,v);push(v,u); }Hash_init(); build(root[0],1,sz); for(int i=1;i<=n;i++)if(!vis[i])dfs(i,0,++num),id[num]=i; while(q--){ char ch=getchar(); while(ch!='Q'&&ch!='L')ch=getchar(); if(ch=='Q'){ int x=read
()^Ans,y=read
()^Ans,k=read
()^Ans; printf("%d\n",Ans=Query(x,y,k)); } else{ int x=read
()^Ans,y=read
()^Ans; if(size[id[belong[x]]]>size[id[belong[y]]])swap(x,y); push(y,x);push(x,y);size[id[belong[y]]]+=size[id[belong[x]]]; dfs(x,y,belong[y]); } }}

转载于:https://www.cnblogs.com/Cooook/p/7738495.html

你可能感兴趣的文章
【SVM】libsvm-python
查看>>
Jmeter接口压力测试,Java.net.BindException: Address already in use: connect
查看>>
Leetcode Balanced Binary Tree
查看>>
go:channel(未完)
查看>>
[JS]递归对象或数组
查看>>
多线程《三》进程与线程的区别
查看>>
linux sed命令
查看>>
html标签的嵌套规则
查看>>
[Source] Machine Learning Gathering/Surveys
查看>>
HTML <select> 标签
查看>>
tju 1782. The jackpot
查看>>
湖南多校对抗赛(2015.03.28) H SG Value
查看>>
hdu1255扫描线计算覆盖两次面积
查看>>
hdu1565 用搜索代替枚举找可能状态或者轮廓线解(较优),参考poj2411
查看>>
bzoj3224 splay板子
查看>>
程序存储问题
查看>>
Mac版OBS设置详解
查看>>
优雅地书写回调——Promise
查看>>
android主流开源库
查看>>
AX 2009 Grid控件下多选行
查看>>