主席树——树链上第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 ...
随机推荐
- SpringBoot配置MySql数据库和Druid连接池
1.pom文件增加相关依赖 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connec ...
- qt 访问容器
#include <iostream> #include <QString> #include <QList> #include <QListIterator ...
- tornado之用户验证装饰器
authenticated装饰器 为了使用Tornado的认证功能,我们需要对登录用户标记具体的处理函数.我们可以使用@tornado.web.authenticated装饰器完成它.当我们使用这个装 ...
- Xcode 打包(Shell)
1. xcodebuild 1.1 查当前可用的 sdk $xcodebuild -showsdks 1.2 查看所支持的target $xcodebuild -target 1.2 清空当前编译的a ...
- audio与video控件/标签的隐藏,iso/Android下自动全屏播放,短暂黑屏问题
(一)audio音频标签 <audio src="xxx.mp3"></audio> (二)video视频标签 <video src="xx ...
- 【简】题解 AWSL090429 【噪音】
因为每次加上一头奶牛 是什么不重要 牛棚之间贡献除清空操作外无影响 就只要考虑 每个牛棚清空分x次 的贡献 x之和为k 求贡献和最小 一个牛棚清空x次 显然平均清空贡献最小 再用等差数列的 ...
- 查看macOS下正在使用的zsh
使用dscl . -read /Users/$USER UserShell查看 如果你的结果是/bin/zsh,又恰巧用brew安装了zsh的话,那么你可能就白安装了 将brew安装的zsh添加到/e ...
- dgraph实现基本操作
dgraph实现基本操作 简单介绍 dgraph 是一个分布式图数据库 mutate 为一个突变, 一般认为添加数据或者是删除数据为一个突变 query 为一个查询 golang实现dgraph的基本 ...
- Bellman-Ford&&SPFA
我们前文说过,有关最短路径除了Floyed算法之外,还有许多更加好的方法.这里讲一下有关 Bellman-Ford和SPFA的知识 Bellman-Ford:复杂度O(VE) 有关Bellman-Fo ...
- MySQL8.0.19主从环境搭建(CentOS7)
默认情况下,复制是异步的,从站不需要永久连接以接收来自主站的更新.根据配置,您可以复制数据库中的所有数据库,所选数据库甚至选定的表. MySQL中复制的优点包括: 横向扩展解决方案 - 在多个从站之间 ...