主席树——树链上第k大spoj COT
首先要求第k大就想到用主席树来处理
但是不能直接用树链剖分的dfs序来维护,因为一条链对应的dfs下标可能是断开的几段,无法用权值线段树来维护
那么久维护每个点到根节点的全值线段树,结点u的权值线段树记录了其到根节点路径上数值的出现次数
主席树相当于维护了一个前缀和,由树上前缀和可以分析出u->v路径上对应的那棵权值线段树应该是
T[u]+T[v]-T[lca]-T[fa[lca]]
所以只要在dfs过程中,结点u依赖fa[u]进行更新主席树即可
那么问题解变成了每个结点u上维护到root的权值线段树,然后每次询问求lca(u,v),再按照上述公式去主席树上查询第k大
求lca可以用树剖,也可以倍增。。
#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
const int N = 1e5+;
struct Node{int lc,rc,sum;}T[N*];
int fa[*N][], dep[*N], vis[N];
int a[N], b[N], tot, cnt, head[N], len;
struct node{int to, next;} p[*N];
void init(){
memset(head,-,sizeof(head));
memset(vis,,sizeof(vis));
cnt=;
return ;
}
void add(int u,int v){
p[cnt].to=v,p[cnt].next=head[u];head[u]=cnt++;
p[cnt].to=u,p[cnt].next=head[v];head[v]=cnt++;
return ;
}
int size,rt[N];
int build(int l,int r){
int now=++size;
T[now].lc=T[now].rc=T[now].sum=;
if(l==r)return now;
int mid=l+r>>;
T[now].lc=build(l,mid);
T[now].rc=build(mid+,r);
return now;
} int update(int l,int r,int last,int pos){//更新到pos点
int now=++size;
T[now]=T[last];T[now].sum++;
if(l==r)return now;
int mid=l+r>>;
if(pos<=mid)T[now].lc=update(l,mid,T[last].lc,pos);
else T[now].rc=update(mid+,r,T[last].rc,pos);
return now;
}
int query(int e1,int e2,int s1,int s2,int l,int r,int k){
if(l==r)return l;
int mid=l+r>>;
int sum=T[T[e1].lc].sum+T[T[e2].lc].sum-T[T[s1].lc].sum-T[T[s2].lc].sum;
if(k<=sum)return query(T[e1].lc,T[e2].lc,T[s1].lc,T[s2].lc,l,mid,k);
else return query(T[e1].rc,T[e2].rc,T[s1].rc,T[s2].rc,mid+,r,k-sum);
} void dfs(int u,int d,int f,int root){
vis[u]=,dep[u]=d,fa[u][]=f;
rt[u]=update(,len,root,a[u]);
for(int i=head[u];i!=-;i=p[i].next){
int v=p[i].to;
if(vis[v]) continue;
dfs(v,d+,u,rt[u]);
}
} int f[maxn],son[maxn],d[maxn],siz[maxn];
void dfs1(int x,int pre,int deep){
f[x]=pre;siz[x]=;d[x]=deep;
for(int i=head[x];i!=-;i=p[i].next){
int y=p[i].to;
if(y==pre)continue;
dfs1(y,x,deep+);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]])son[x]=y;
}
}
int id[maxn],rk[maxn],idx,top[maxn];
void dfs2(int x,int tp){
top[x]=tp;id[x]=++idx;rk[idx]=x;
if(son[x])dfs2(son[x],tp);
for(int i=head[x];i!=-;i=p[i].next){
int y=p[i].to;
if(y!=son[x] && y!=f[x])dfs2(y,y);
}
}
int Query(int x,int y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]])swap(x,y);
x=f[top[x]];
}
if(id[x]>id[y])swap(x,y);
return x;
} int main(){
int t, n, q;
scanf("%d %d", &n, &q);
for(int i=; i<=n; i++) scanf("%d", &a[i]), b[i]=a[i];
sort(b+,b+n+);
len=unique(b+,b+n+)-(b+);
tot=;
rt[]=build(,len);
for(int i=; i<=n; i++) a[i]=lower_bound(b+,b+len+,a[i])-(b);
init();
for(int i=;i<n-;i++){
int x, y;
scanf("%d %d", &x, &y);
add(x,y);
}
dfs(,,,rt[]);dfs1(,,),dfs2(,);
int ans=;
while(q--){
int l, r, x;
scanf("%d %d %d", &l, &r, &x);l^=ans;
int pos=Query(l,r);
printf("%d\n",ans=b[query(rt[l],rt[r],rt[pos],rt[fa[pos][]],,len,x)]);
}
return ;
}
主席树——树链上第k大spoj COT的更多相关文章
- 树上主席树 - 查询树链上第K大
Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...
- HDU 5249 离线树状数组求第k大+离散化
KPI Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- 可持久化线段树(主席树)——静态区间第k大
主席树基本操作:静态区间第k大 #include<bits/stdc++.h> using namespace std; typedef long long LL; ,MAXN=2e5+, ...
- 主席树 - 查询某区间第 K 大
You are working for Macrohard company in data structures department. After failing your previous tas ...
- 洛谷P2617 Dynamic Rankings 主席树 单点修改 区间查询第 K 大
我们将线段树套在树状数组上,查询前预处理出所有要一起移动的节点编号,并在查询过程中一起将这些节点移到左右子树上. Code: #include<cstdio> #include<cs ...
- 主席树(静态区间第k大)
前言 如果要求一些数中的第k大值,怎么做? 可以先就这些数离散化,用线段树记录每个数字出现了多少次. ... 那么考虑用类似的方法来求静态区间第k大. 原理 假设现在要有一些数 我们可以对于每个数都建 ...
- 主席树入门——询问区间第k大pos2104,询问区间<=k的元素个数hdu4417
poj2104找了个板子..,但是各种IO还可以进行优化 /* 找区间[l,r]第k大的数 */ #include<iostream> #include<cstring> #i ...
- 【大杀器】利用划分树秒杀区间内第k大的数
最近看了一道题,大概就是给出一个序列,不断询问其子区间内第k大的数,下面是个截图 绕了一圈没找到中文版题目,if(你是大佬) then 去看截图:else{我来解释:给出一个整数n,和一个整数m,分别 ...
- POJ2985 The k-th Largest Group[树状数组求第k大值+并查集||treap+并查集]
The k-th Largest Group Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 8807 Accepted ...
随机推荐
- 常见的cmd命令
1.查看所有端口的使用情况:netstat -ano
- layui table默认选中指定行
表格默认选中行,在回调里写入 done: function (res, curr, count) { tableData = res.data; $("[data-field='id']&q ...
- 百度编辑器前后端二开图片上传Js Thinkphp tp5 ueditor
百度编辑器图片上传Jsueditor.all.min.js 下载链接 链接:https://pan.baidu.com/s/1VNgw9ELgRRHKeCQheFkQTw 提取码:fnfi 使用方法: ...
- web技术应用分享
https://www.helloweba.com/nav.html Helloweba为广大前端开发者收录了常用实用的前端资源工具,方便大家学习和查阅. https://www.hello ...
- 2. Java内存区域
Java 虚拟机的内存模型分为两部分:一部分是线程共享的,包括 Java 堆和方法区:另一部分是线程私有的,包括虚拟机栈和本地方法栈,以及程序计数器这一小部分内存 2.1 程序计数器 程序计数器(Pr ...
- 制作OpenStack使用的windows镜像
1 安装vmware14 2 创建ubuntu-desktop-16.04虚拟机 选择自定义安装 选择ubuntu-16.04-desktop.iso 内存要大于2G,推荐4G. 磁盘要大于50G 关 ...
- SOA 和 微服务
正在读 钟华 著的<<企业IT架构转型之道 - 阿里巴巴中台战略思想与架构实战>> 一书, 参考了网上的讨论, 对SOA和微服务有了一些新的认识. 知乎上的讨论: SOA 与 ...
- 解决系统中大量的TIME_WAIT连接
今天发现网站特别卡!! 查看网络连接数: netstat -an |wc -l netstat -an |grep xx |wc -l 查看某个/特定ip的连接数 netstat -an ...
- python3 练手实例5 做一个简单电子时钟
import time,sys,os while(1): t = time.strftime('%Y-%m-%d\n%H:%M:%S',time.localtime(time.time())) pri ...
- Tree Cutting POJ - 2378 (树形DP)
题目链接:POJ - 2378 题目大意:给你n个点,然后问你这n个点中 ,去除哪些点能够使得剩下的图中最大的连通块中点的个数不超过n/2. 具体思路:第一遍dfs记录每一个点代表的子树大小,第二遍d ...