BZOJ 3123 森林(函数式线段树)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3123
题意:

思路:总的来说,查询区间第K小利用函数式线段树的减法操作。对于两棵树的合并,将节点少的树暴力插入到节点大的树上面。对于本题,首先,将输入的权值离散化,为已经给出的边建立函数式线段树。对于合并x,y,将y的父节点设为x,然后重新建立y为根的子树的函数式线段树。对于查询x,y,k,设其LCA为p,p的父节点为q,则x+y-p-q就是整个区间。
struct node
{
int L,R,s;
};
node tree[N*400];
int root[N],tot;
int f[N][20],w[N],n,m,K,d[N],size[N];
vector<int> g[N];
int M;
int b[N];
int build(int a,int b)
{
int k=++tot;
tree[k].s=0;
if(a==b) return k;
int mid=(a+b)>>1;
tree[k].L=build(a,mid);
tree[k].R=build(mid+1,b);
return k;
}
int insert(int c,int s,int a,int b)
{
int k=++tot;
tree[k]=tree[c];
tree[k].s++;
if(a==b) return k;
int mid=(a+b)>>1;
if(s<=mid) tree[k].L=insert(tree[c].L,s,a,mid);
else tree[k].R=insert(tree[c].R,s,mid+1,b);
return k;
}
int visit[N],X;
void BFS(int u)
{
queue<int> Q;
Q.push(u);
int i,v;
while(!Q.empty())
{
u=Q.front();
Q.pop();
visit[u]=X;
root[u]=insert(root[f[u][0]],w[u],0,M);
for(i=1;i<20;i++) f[u][i]=f[f[u][i-1]][i-1];
FOR0(i,SZ(g[u]))
{
v=g[u][i];
if(visit[v]==X) continue;
f[v][0]=u;
d[v]=d[u]+1;
Q.push(v);
}
}
}
int get(int x,int k)
{
int i;
FOR0(i,20) if(k&(1<<i)) x=f[x][i];
return x;
}
int getLca(int x,int y)
{
if(d[x]>d[y]) swap(x,y);
y=get(y,d[y]-d[x]);
if(x==y) return x;
int i;
for(i=19;i>=0;i--) if(f[x][i]&&f[y][i]&&f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
return f[x][0];
}
#define L(a) tree[tree[a].L].s
int query(int a,int b,int c,int d,int k,int L,int R)
{
if(L==R) return L;
int s=L(a)+L(b)-L(c)-L(d);
int mid=(L+R)>>1;
if(k<=s) return query(tree[a].L,tree[b].L,tree[c].L,tree[d].L,k,L,mid);
return query(tree[a].R,tree[b].R,tree[c].R,tree[d].R,k-s,mid+1,R);
}
void go()
{
int x,y,k,p,last=0;
char op[10];
int fx,fy;
while(K--)
{
RD(op);
if(op[0]=='Q')
{
RD(x,y,k);
x^=last; y^=last; k^=last;
p=getLca(x,y);
last=b[query(root[x],root[y],root[p],root[f[p][0]],k,0,M)];
PR(last);
}
else
{
RD(x,y);
x^=last; y^=last;
fx=get(x,d[x]);
fy=get(y,d[y]);
g[x].pb(y);
g[y].pb(x);
X++;
if(size[fx]>=size[fy])
{
size[fx]+=size[fy];
f[y][0]=x;
d[y]=d[x]+1;
visit[x]=X;
BFS(y);
}
else
{
size[fy]+=size[fx];
f[x][0]=y;
d[x]=d[y]+1;
visit[y]=X;
BFS(x);
}
}
}
}
int main()
{
int CC;
RD(CC);
RD(n,m,K);
int i,j,u,v;
FOR1(i,n) RD(w[i]),size[i]=1,b[i]=w[i];
sort(b+1,b+n+1);
M=unique(b+1,b+n+1)-(b+1);
FOR1(i,n) w[i]=lower_bound(b+1,b+M+1,w[i])-b;
tot=0;
root[0]=build(0,M);
FOR1(i,m)
{
RD(u,v);
g[u].pb(v);
g[v].pb(u);
}
FOR1(i,n) f[i][0]=-1;
FOR1(i,n) if(f[i][0]==-1)
{
f[i][0]=0; d[i]=0; X++;
BFS(i);
}
go();
}
BZOJ 3123 森林(函数式线段树)的更多相关文章
- bzoj 3123 可持久化线段树启发式合并
首先没有连边的操作的时候,我们可以用可持久化线段树来维护这棵树的信息,建立权值可持久化线段树,那么每个点继承父节点的线段树,当询问为x,y的时候我们可以询问rot[x]+rot[y]-rot[lca( ...
- BZOJ 3207 花神的嘲讽计划Ⅰ(函数式线段树)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3207 题意:给出一个数列,若干询问.每个询问查询[L,R]区间内是否存在某个长度为K的子 ...
- 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))
函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...
- POJ2104 K-th number 函数式线段树
很久没打代码了,不知道为什么,昨天考岭南文化之前突然开始思考起这个问题来,这个问题据说有很多种方法,划分树什么的,不过对于我现在这种水平还是用熟悉的线段树做比较好.这到题今年8月份的时候曾经做过,那个 ...
- [Usaco2014 Open Gold ]Cow Optics (树状数组+扫描线/函数式线段树)
这道题一上手就知道怎么做了= = 直接求出原光路和从目标点出发的光路,求这些光路的交点就行了 然后用树状数组+扫描线或函数式线段树就能过了= = 大量的离散+模拟+二分什么的特别恶心,考试的时候是想到 ...
- hdu 5111 树链剖分加函数式线段树
这题说的是给了两棵树,各有100000 个节点,然后Q个操作Q<=50000; 每个操作L1 R1 L2 R2.因为对于每棵树都有一个与本棵树其他点与众不同的值, 最后问 在树上从L1到R1这条 ...
- Codeforces538F A Heap of Heaps(函数式线段树)
题意:给你一个数组a[n],对于数组每次建立一个完全k叉树,对于每个节点,如果父节点的值比这个节点的值大,那么就是一个违规点,统计出1~n-1完全叉树下的违规点的各自的个数. 一个直觉的思想就是暴力, ...
- Bzoj 2752 高速公路 (期望,线段树)
Bzoj 2752 高速公路 (期望,线段树) 题目链接 这道题显然求边,因为题目是一条链,所以直接采用把边编上号.看成序列即可 \(1\)与\(2\)号点的边连得是. 编号为\(1\)的点.查询的时 ...
- BZOJ - 3123 森林 (可持久化线段树+启发式合并)
题目链接 先把初始边建成一个森林,每棵树选一个根节点递归建可持久化线段树.当添加新边的时候,把结点数少的树暴力重构,以和它连边的那个点作为父节点继承线段树,并求出倍增数组.树的结点数可以用并查集来维护 ...
随机推荐
- always语言指导原则
1.每个always只有一个@(event-expression). 2.always块可以表示时序逻辑和组合逻辑. 3.带有posedge和negedge关键字的是表示沿触发的时序逻辑,没有的表示组 ...
- 怎样在cmd(命令提示符)下进行复制粘贴操作
如右图,右键命令提示符窗口的标题栏,选择属性. 选择“编辑选项”里的“快速编辑模式”,并确定之: 在弹出的应用选择提示框上选择“保存属性,供以后具有相同标题的窗口使用”: 如此你就可以 ...
- STL学习二:Vector容器
1.Vector容器简介 vector是将元素置于一个动态数组中加以管理的容器. vector可以随机存取元素(支持索引值直接存取, 用[]操作符或at()方法,这个等下会详讲). vector尾部添 ...
- Oracle 多行记录合并/连接/聚合字符串的几种方法
怎么合并多行记录的字符串,一直是oracle新手喜欢问的SQL问题之一,关于这个问题的帖子我看过不下30个了,现在就对这个问题,进行一个总结.-什么是合并多行字符串(连接字符串)呢,例如: SQL&g ...
- [Android] ImageView.ScaleType设置图解 【转载】
ImageView的Scaletype决定了图片在View上显示时的样子,如进行何种比例的缩放,及显示图片的整体还是部分,等等. 设置的方式包括: 1. 在layout xml中定义android:s ...
- ACCESS数据库C#操作类(包含事务)
转自http://blog.csdn.net/allen3010/article/details/6336717 这个是针对ACCESS数据库操作的类,同样也是从SQLHELPER提取而来,分页程序的 ...
- C++实现简单的内存池
多进程编程多用在并发服务器的编写上,当收到一个请求时,服务器新建一个进程处理请求,同时继续监听.为了提高响应速度,服务器采用进程池的方法,在初始化阶段创建一个进程池,池中有许多预创建的进程,当请求到达 ...
- FZU 2016 summer train I. Approximating a Constant Range 单调队列
题目链接: 题目 I. Approximating a Constant Range time limit per test:2 seconds memory limit per test:256 m ...
- Matlab中@与函数调用
function m f=@(x) x^2; y(f,3); function y(f,x) disp(num2str(f(x))); end end 函数调用另一个函数的时候,把另一个函数名作为参数 ...
- [C/CPP系列知识] 那些程序C语言可以编译通过但C++无法编译成功 Write a C program that won’t compile in C++
http://www.geeksforgeeks.org/write-c-program-wont-compiler-c/ 1) C++中在函数声明之前调用一个函数会引发错误,但是在C中有可能可以. ...