3123: [Sdoi2013]森林
3123: [Sdoi2013]森林
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 3336 Solved: 978
[Submit][Status][Discuss]
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。之后的操作类似。
Source
/*
平常这种题很常见的思路就是求出dfs序来,然后每次查询的时候就是在主席树上查询 x+y-lca-fa[lca] 的值就行了。
但是这个题要动态的给森林中加边,还是强制在线的,所以就需要考虑换一种方法来维护这个东西。
首先先dfs出每棵树来,然后对于link操作,可以启发式合并两个主席树。这里我们把主席树维护的dfs序变成维护每个点到根的这条路径。所里link的时候假设我们要把x合到y上,那么我们就边dfs x 这棵树,边用当前点的fa作为历史状态的root来更新当前点的root就行了。求lca的fa数组和deep数组在dfs的时候动态维护就行了。
复杂度: O(nlog2n)
*/
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1e5+;
const int M=2e7+;
const int inf=1e9;
int n,m,T,sz,num,ans,val[N],dep[N],siz[N],belong[N],fa[N][];bool flag[N];
struct edge{int u,v,next;}e[N<<];int tot,head[N];
int root[N],R[N],sum[M],ls[M],rs[M];
inline int read(){
int x=;char ch=getchar();
while(ch<''||ch>''){ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x;
}
inline void add(int x,int y){
e[++tot].v=y;e[tot].next=head[x];head[x]=tot;
e[++tot].v=x;e[tot].next=head[y];head[y]=tot;
}
void insert(int &k,int last,int l,int r,int pos){
k=++sz;
sum[k]=sum[last]+;
if(l==r) return ;
ls[k]=ls[last];
rs[k]=rs[last];
int mid=l+r>>;
if(pos<=mid) insert(ls[k],ls[last],l,mid,pos);
else insert(rs[k],rs[last],mid+,r,pos);
}
void dfs(int x,int f,int now){
flag[x]=;siz[x]=;belong[x]=now;
for(int i=;i<;i++) fa[x][i]=fa[fa[x][i-]][i-];
insert(root[x],root[f],,inf,val[x]);
for(int i=head[x];i;i=e[i].next){
if(e[i].v!=f){
fa[e[i].v][]=x;
dep[e[i].v]=dep[x]+;
dfs(e[i].v,x,now);
siz[x]+=siz[e[i].v];
}
}
}
inline int lca(int a,int b){
if(dep[a]<dep[b]) swap(a,b);
int t=dep[a]-dep[b];
for(int i=;i<;i++){
if(t&(<<i)){
a=fa[a][i];
}
}
if(a==b) return a;
for(int i=;~i;i--){
if(fa[a][i]!=fa[b][i]){
a=fa[a][i];
b=fa[b][i];
}
}
return fa[a][];
}
int query(int l,int r,int x1,int x2,int x3,int x4,int pos){
if(l==r) return l;
int now=sum[ls[x1]]+sum[ls[x2]]-sum[ls[x3]]-sum[ls[x4]];
int mid=l+r>>;
if(now>=pos) return query(l,mid,ls[x1],ls[x2],ls[x3],ls[x4],pos);
return query(mid+,r,rs[x1],rs[x2],rs[x3],rs[x4],pos-now);
}
int main(){
freopen("forest.in","r",stdin);
freopen("forest.out","w",stdout);
T=read();n=read();m=read();T=read();
for(int i=;i<=n;i++) val[i]=read();
for(int i=,x,y;i<=m;i++) x=read(),y=read(),add(x,y);
for(int i=;i<=n;i++) if(!flag[i]) dfs(i,,++num),R[num]=i;
for(int x,y,z,anc;T--;){
char ch;
for(ch=getchar();ch!='Q'&&ch!='L';ch=getchar());
x=read();y=read();
x^=ans;y^=ans;
if(ch=='Q'){
z=read();z^=ans;
anc=lca(x,y);
ans=query(,inf,root[x],root[y],root[anc],root[fa[anc][]],z);
printf("%d\n",ans);
}
else{
if(siz[R[belong[x]]]>siz[R[belong[y]]]) swap(x,y);
add(y,x);
fa[x][]=y;
siz[R[belong[y]]]+=siz[R[belong[x]]];
dep[x]=dep[y]+;
dfs(x,y,belong[y]);
}
}
return ;
}
/*10
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll; #define setfire(name) freopen(#name".in","r",stdin);freopen(#name".out","w",stdout);
#define fre(name) freopen(#name".txt","r",stdin);
#ifdef WIN32
#define LL "%lld"
#else
#define LL "%I64d"
#endif const int N=1e5+5;
int cas,n,m,t,ans,val[N],tv[N],stack[N],prev[N];bool vis[N];
struct edge{int v,next;}e[N<<1];int tot,head[N];
char s[50]; inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9'){ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
inline void add(int x,int y){
e[++tot].v=y;e[tot].next=head[x];head[x]=tot;
e[++tot].v=x;e[tot].next=head[y];head[y]=tot;
}
inline void bfs(int S,int T){
int top=1;stack[top]=S;
memset(vis,0,(n+2));
memset(prev,0,(n+2)<<2);
while(top){
int x=stack[top--];
for(int i=head[x];i;i=e[i].next){
if(!vis[e[i].v]){
vis[e[i].v]=1;
prev[e[i].v]=x;
if(e[i].v==T) return ;
stack[++top]=e[i].v;
}
}
}
}
inline void calc(int S,int T,int rk){
tv[0]=0;
for(int i=T;i!=S;i=prev[i]) tv[++tv[0]]=val[i];tv[++tv[0]]=val[S];
nth_element(tv+1,tv+rk,tv+tv[0]+1);
printf("%d\n",ans=tv[rk]);
}
void init(){
tot=0;
memset(head,0,(n+2)<<2);
}
int main(){
freopen("forest.in","r",stdin);
freopen("forest.out","w",stdout);
//for(cas=read();init(),cas--;){
cas=read();
n=read();m=read();t=read();
for(int i=1;i<=n;i++) val[i]=read();
for(int i=1,x,y;i<=m;i++) x=read(),y=read(),add(x,y);
for(int x,y,z;t--;){
scanf("%s",s);
if(s[0]=='Q'){
x=read();y=read();z=read();
x^=ans;y^=ans;z^=ans;
bfs(x,y);
calc(x,y,z);
}
else{
x=read();y=read();
x^=ans;y^=ans;
add(x,y);
}
}
// }
return 0;
} */
UPD.2017-04-24
/*
Name: forest
Copyright: @2016-2017 shenben
Author: shenben
Date: 24/04/17 14:56
Description: Algorithm chairman tree & Heuristic mergeing
*/
#include<cstdio>
//#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+;
const int M=N*;
struct edge{int v,next;}e[N<<];int tot,head[N];
int n,m,num,cnt,T,sz,a[N],b[N];char s[];
int siz[N],dep[N],fa[N][],R[N],belong[N];bool flag[N];
int root[N],ls[M],rs[M],sum[M];
inline int read(){
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
void add(int x,int y){
e[++tot].v=y;e[tot].next=head[x];head[x]=tot;
e[++tot].v=x;e[tot].next=head[y];head[y]=tot;
}
void insert(int &k,int last,int l,int r,int x){
k=++sz;
sum[k]=sum[last]+;
if(l==r) return ;
ls[k]=ls[last];
rs[k]=rs[last];
int mid=l+r>>;
if(x<=mid) insert(ls[k],ls[last],l,mid,x);
else insert(rs[k],rs[last],mid+,r,x);
}
int query(int l,int r,int x1,int x2,int x3,int x4,int K){
if(l==r) return l;
int mid=l+r>>;
int cnt=sum[ls[x1]]+sum[ls[x2]]-sum[ls[x3]]-sum[ls[x4]];
if(K<=cnt) return query(l,mid,ls[x1],ls[x2],ls[x3],ls[x4],K);
else return query(mid+,r,rs[x1],rs[x2],rs[x3],rs[x4],K-cnt);
}
void dfs(int x,int f,int now){
flag[x]=;siz[x]=;belong[x]=now;
for(int i=;i<;i++) fa[x][i]=fa[fa[x][i-]][i-];
int p=lower_bound(b+,b+cnt+,a[x])-b;
insert(root[x],root[f],,cnt,p);
for(int i=head[x];i;i=e[i].next){
if(e[i].v!=f){
fa[e[i].v][]=x;
dep[e[i].v]=dep[x]+;
dfs(e[i].v,x,now);
siz[x]+=siz[e[i].v];
}
}
}
inline int lca(int a,int b){
if(dep[a]<dep[b]) swap(a,b);
int t=dep[a]-dep[b];
for(int i=;i<;i++){
if(t&(<<i)){
a=fa[a][i];
}
}
if(a==b) return a;
for(int i=;~i;i--){
if(fa[a][i]!=fa[b][i]){
a=fa[a][i];
b=fa[b][i];
}
}
return fa[a][];
}
int main(){
freopen("forest.in","r",stdin);
freopen("forest.out","w",stdout);
/*int size=64<<20;
char *p=(char *)malloc(size)+size;
__asm__("movl %0,%%esp\n"::"r"(p));*/
T=read();n=read();m=read();T=read();
for(int i=;i<=n;i++) b[i]=a[i]=read();
sort(b+,b+n+);
cnt=unique(b+,b+n+)-(b+);
for(int i=,x,y;i<=m;i++) x=read(),y=read(),add(x,y);
for(int i=;i<=n;i++) if(!flag[i]) flag[i]=,dfs(i,,++num),R[num]=i;
for(int i=,x,y,z,anc,ans=;i<=T;i++){
scanf("%s",s);x=read()^ans;y=read()^ans;
if(s[]=='Q'){
anc=lca(x,y);z=read()^ans;
ans=query(,cnt,root[x],root[y],root[anc],root[fa[anc][]],z);
printf("%d\n",ans=b[ans]);
}
else{
if(siz[R[belong[x]]]>siz[R[belong[y]]]) swap(x,y);
add(x,y);
fa[x][]=y;
dep[x]=dep[y]+;
siz[R[belong[y]]]+=siz[R[belong[x]]];
dfs(x,y,belong[y]);
}
}
fclose(stdin);fclose(stdout);
return ;
}
3123: [Sdoi2013]森林的更多相关文章
- BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]
3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...
- bzoj 3123: [Sdoi2013]森林(45分暴力)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4184 Solved: 1235[Submit][Status ...
- Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...
- ●BZOJ 3123 [Sdoi2013]森林
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3123 题解: 主席树,在线,启发式合并 简单版(只有询问操作):[2588: Spoj 10 ...
- BZOJ 3123 [SDOI2013] 森林 - 启发式合并 主席树
Description 给你一片森林, 支持两个操作: 查询$x$到$y$的$K$大值, 连接两棵树中的两个点 Solution 对每个节点$x$动态开权值线段树, 表示从$x$到根节点路径上权值出 ...
- BZOJ 3123 SDOI2013 森林
首先对于查询操作就是裸的COT QAQ 在树上DFS建出主席树就可以了 对于连接操作,我们发现并没有删除 所以我们可以进行启发式合并,每次将小的树拍扁插入大的树里并重构即可 写完了之后第一个和第二个点 ...
- bzoj 3123 [Sdoi2013]森林(主席树,lca,启发式合并)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- bzoj 3123 [Sdoi2013]森林(主席树+启发式合并+LCA)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- 【BZOJ】3123: [Sdoi2013]森林
题解 ------------------ 我莫不是一个智障吧 我把testdata的编号 当成数据组数读进来 我简直有毒 以为哪里写错了自闭了好久 实际上这题很简单,只要愉悦地开个启发式合并,然后每 ...
随机推荐
- 用ASP实现JS的decodeURIComponent()函数
<% response.write jsDecodeURIComponent( "%E6%B5%8B%E8%AF%95" ) %> <script languag ...
- SuperMap iClient如何使用WMTS地图服务(转)
http://blog.sina.com.cn/s/blog_6259ebd50102v221.html 什么是WMTS服务 WMTS,切片地图Web服务(Web Map Tile Service)当 ...
- Java 中 ConcurrentHashMap 原理分析
一.Java并发基础 当一个对象或变量可以被多个线程共享的时候,就有可能使得程序的逻辑出现问题. 在一个对象中有一个变量i=0,有两个线程A,B都想对i加1,这个时候便有问题显现出来,关键就是对i加1 ...
- JPEG编码(一)
JPEG编码介绍. 转自:http://blog.chinaunix.net/uid-20451980-id-1945156.html JPEG(Joint Photographic Experts ...
- Mysql_SQL_常用知识点&实践
1.Mysql中类似于nvl()函数的ifnull()函数 ) FROM Table 2.添加某个字段(指定字段column的位置) ----------添加字段zoneId ) NOT NULL A ...
- CountDownLatch模拟高并发测试代码
直接上代码进行验证吧 /** * 通过countdownlatch的机制,来实现并发运行 * 模拟200个并发测试 * @author ll * @date 2018年4月18日 下午3:55:59 ...
- k8s restful API 结构分析
k8s的api-server组件负责提供restful api访问端点, 并且将数据持久化到etcd server中. 那么k8s是如何组织它的restful api的? 一, namespaced ...
- Linux学习之三-Linux系统的一些重要配置文件
Linux学习之三-Linux系统的一些重要配置文件 1.网卡配置文件 /etc/sysconfig/network-scripts/ifcfg-eth0 说明: DEVICE=eth0 ...
- mysql left join查询没走索引
SELECT t0.ID as id, t0.`NAME` as name, t0.PHONE as phone, t0.`CITY_CODE` as cityCode, t0.SHOOTING_TI ...
- Android控件常见属性
1.宽/高android:layout_width android:layout_height// 取值match_parent //匹配父控件wrap_content //自适应,根据内容 如果指定 ...