题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=3551

题解:

最小生成树 Kruskal,主席树,在线

这个做法挺巧妙的。。。
以Kruskal算法为基础,如果在用边 e(u,v,w) 合并 u 和 v 所在的联通块时,
我们新加一个节点 x(同时给它一个权值 w,即边 e 的权值),
使得 u的联通块和 v的联通块通过这个节点 x 来合并为一个联通块。

那么当Kruskal算法完成时,那么也就生成了一颗二叉树。

不难发现,这个二叉树非常棒啊:
1).叶子代表原图中的点,共有 N 个叶子
2).对于一个节点 x 来说,如果其点权为 w,
则表明 x 的子树的叶子节点所代表的的那些原图中的点可以通过边权不超过 w 的边互相通达。

所以按照如上方法生成了一颗二叉树后,
dfs一遍计算出每个节点所包含叶子节点的范围
(l[u],r[u]表示 u 这个节点的所包含叶子节点的范围是第 l[u]个叶子到第 R[u]个叶子)
然后按照叶子节点的顺序对原图的点的高度建立主席树。

每次查询v,x,k时,
就在二叉树中从该叶子向上倍增,
找到一个最大的子树使得该子树的根的权值不超过 x
然后得到范围 l[x] r[x],并在主席树 rt[l[x]-1]~rt[r[x]] 中查询第 k 大就好了。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 105000
using namespace std;
int H[MAXN],tmp[MAXN],Ord[MAXN];
int N,M,Q,tnt,Ont;
struct Edge{
int u,v,w;
bool operator <(const Edge &rtm)const{
return w<rtm.w;
}
}E[MAXN*5];
struct CMT{
int rt[MAXN],ls[MAXN*20],rs[MAXN*20],cnt[MAXN*20],sz;
void Insert(int &u,int l,int r,int p){
sz++; cnt[sz]=cnt[u]; ls[sz]=ls[u]; rs[sz]=rs[u];
u=sz; cnt[u]++;
if(l==r) return;
int mid=(l+r)>>1;
if(p<=mid) Insert(ls[u],l,mid,p);
else Insert(rs[u],mid+1,r,p);
}
int Query(int v,int u,int l,int r,int K){
if(l==r) return l;
int mid=(l+r)>>1,rcnt=cnt[rs[u]]-cnt[rs[v]];
if(K<=rcnt) return Query(rs[v],rs[u],mid+1,r,K);
else return Query(ls[v],ls[u],l,mid,K-rcnt);
}
void Build(){
for(int i=1;i<=N;i++){
rt[i]=rt[i-1];
Insert(rt[i],1,tnt,H[Ord[i]]);
}
}
}DT;//维护成重构的二叉树的底层叶子节点信息的主席树
struct BT{
int bel[MAXN*2],ls[MAXN*2],rs[MAXN*2],l[MAXN*2],r[MAXN*2],val[MAXN*2],fa[MAXN*2][20];
int sz,rt;
void Newnode(int u,int lson,int rson,int w){
val[u]=w; bel[lson]=u; bel[rson]=u;
ls[u]=lson; rs[u]=rson;
}
int Find(int x){
return x==bel[x]?x:bel[x]=Find(bel[x]);
}
void Dfs(int u,int f){
fa[u][0]=f;
for(int k=1;k<20;k++){
if(!fa[u][k-1]||!fa[fa[u][k-1]][k-1]) break;
fa[u][k]=fa[fa[u][k-1]][k-1];
}
if(!ls[u]&&!rs[u]){
Ord[++Ont]=u; l[u]=r[u]=Ont;
return;
}
Dfs(ls[u],u); Dfs(rs[u],u);
l[u]=l[ls[u]]; r[u]=r[rs[u]];
}
void Build(){
sz=N;
for(int i=1;i<=2*N;i++) bel[i]=i;
for(int i=1,fu,fv;i<=M;i++){
fu=Find(E[i].u);
fv=Find(E[i].v);
if(fu==fv) continue;
Newnode(++sz,fu,fv,E[i].w);
}
rt=sz; Dfs(rt,0);
}
int Query(int u,int w,int K){
for(int k=19;k>=0;k--){
if(!fa[u][k]||val[fa[u][k]]>w) continue;
u=fa[u][k];
}
int lrt=DT.rt[l[u]-1],rrt=DT.rt[r[u]];
if(DT.cnt[rrt]-DT.cnt[lrt]<K) return -1;
return tmp[DT.Query(lrt,rrt,1,tnt,K)];
}
}GT;//根据Kruskal重构的二叉树
void read(int &x){
static int f; static char ch;
x=0; f=1; ch=getchar();
while(ch<'0'||'9'<ch){if(ch=='-') f=-1; ch=getchar();}
while('0'<=ch&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
x=x*f;
}
void readin(){
read(N); read(M); read(Q);
for(int i=1;i<=N;i++) read(H[i]),tmp[i]=H[i];
sort(tmp+1,tmp+N+1);
tnt=unique(tmp+1,tmp+N+1)-tmp-1;
for(int i=1;i<=N;i++)
H[i]=lower_bound(tmp+1,tmp+tnt+1,H[i])-tmp;
for(int i=1;i<=M;i++)
read(E[i].u),read(E[i].v),read(E[i].w);
sort(E+1,E+M+1);
}
void answer(){
static int V,X,K,lastANS;
for(int i=1;i<=Q;i++){
scanf("%d%d%d",&V,&X,&K);
if(lastANS!=-1) V^=lastANS,X^=lastANS,K^=lastANS;
lastANS=GT.Query(V,X,K);
printf("%d\n",lastANS);
}
}
int main(){
readin();
GT.Build();
DT.Build();
answer();
return 0;
}

●BZOJ 3551 [ONTAK2010]Peaks(在线)的更多相关文章

  1. BZOJ 3551: [ONTAK2010]Peaks加强版 [Kruskal重构树 dfs序 主席树]

    3551: [ONTAK2010]Peaks加强版 题意:带权图,多组询问与一个点通过边权\(\le lim\)的边连通的点中点权k大值,强制在线 PoPoQQQ大爷题解传送门 说一下感受: 容易发现 ...

  2. bzoj 3551: [ONTAK2010]Peaks加强版

    Description [题目描述]同3545 Input 第一行三个数N,M,Q. 第二行N个数,第i个数为h_i 接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径. 接下来 ...

  3. BZOJ.3551.[ONTAK2010]Peaks加强版(Kruskal重构树 主席树)

    题目链接 \(Description\) 有n个座山,其高度为hi.有m条带权双向边连接某些山.多次询问,每次询问从v出发 只经过边权<=x的边 所能到达的山中,第K高的是多少. 强制在线. \ ...

  4. bzoj 3551 [ONTAK2010]Peaks加强版(kruskal,主席树,dfs序)

    Description [题目描述]同3545 Input 第一行三个数N,M,Q. 第二行N个数,第i个数为h_i 接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径. 接下来 ...

  5. 【刷题】BZOJ 3551 [ONTAK2010]Peaks加强版

    Description [题目描述]同3545 Input 第一行三个数N,M,Q. 第二行N个数,第i个数为h_i 接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径. 接下来 ...

  6. BZOJ 3551: [ONTAK2010]Peaks加强版 Kruskal重构树+dfs序+主席树+倍增

    建出来 $Kruskal$ 重构树. 将询问点向上跳到深度最小,且合法的节点上. 那么,得益于重构树优美的性质,这个最终跳到的点为根的所有子节点都可以与询问点互达. 对于子树中求点权第 $k$ 大的问 ...

  7. 3551: [ONTAK2010]Peaks加强版

    3551: [ONTAK2010]Peaks加强版 https://www.lydsy.com/JudgeOnline/problem.php?id=3551 分析: kruskal重构树 +  倍增 ...

  8. bzoj 3545&&3551: [ONTAK2010]Peaks &&加强版 平衡树&&并查集合并树&&主席树

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Stat ...

  9. bzoj 3545/3551: [ONTAK2010]Peaks -- 主席树,最小生成树,倍增

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MB Description 在Bytemountains有N座山峰,每座山峰 ...

随机推荐

  1. 团队作业7——第二次项目冲刺(Beta版本12.06)

    项目每个成员的进展.存在问题.接下来两天的安排. 已完成的内容:队员每个人提出对接下来需要做的事情的看法和意见,将需要做的任务更新到了leangoo中进行管理,产品完成了界面优化的设计,测试复现了之前 ...

  2. JAVA中最容易让人忽视的基础。

    可能很多找编程工作的人在面试的时候都有这种感受,去到一个公司填写面试试题的时候,多数人往往死在比较基础的知识点上.不要奇怪,事实就是如此一般来说,大多数公司给出的基础题大概有122道,代码题19道左右 ...

  3. c语言中宏定义和常量定义的区别

    他们有共同的好处就是"一改全改,避免输入错误"哪两者有不同之处吗?有的. 主要区别就在于,宏定义是在编译之前进行的,而const是在编译阶段处理的 宏定义不占用内存单元而const ...

  4. 你考虑清楚了吗就决定用 Bootstrap ?

    近年来,在前端项目中, Bootstrap 已经成为了一个非常受欢迎的工具. Bootstrap 的确有很多优点,然而,如果你的团队中恰好有一个专职的前端工程师.那我推荐你们不要使用 Bootstra ...

  5. Linux探索之路1---CentOS入坑笔记整理

    前言 上次跟运维去行方安装行内环境,发现linux命令还是不是很熟练.特别是用户权限分配以及vi下的快捷操作.于是决定在本地安装一个CentOS虚拟机,后面有时间就每天学习一点Linux常用命令. 作 ...

  6. Centos6.9minimal安装图形化界面

    有时我们会用到图形化界面来操作,下面介绍是在虚拟机上安装Centos6.9minimal版安装图形化界面(其他系统版本都类似吧,,,),如果是在物理机上安装进入的话要用的远程桌面工具VNC. VNC安 ...

  7. vi和vim编辑器

    VI vi是一种计算机文本编辑器,由美国计算机科学家比尔·乔伊(Bill Joy)完成编写,并于1976年以BSD协议授权发布. VIM Vim是从vi发展出来的一个文本编辑器.其代码补完.编译及错误 ...

  8. POJ-1328 Radar Installation--区间选点问题(贪心)

    题目链接: https://vjudge.net/problem/POJ-1328 题目大意: 假设陆地的海岸线是一条无限延长的直线,海岛是一个个的点,现需要在海岸线上安装雷达,使整个雷达系统能够覆盖 ...

  9. JS面向对象使用面向对象进行开发

      面向对象基础一之初体验使用面向对象进行开发 对 JS 中的面向对象的基础进行讲述, 初体验使用面向对象进行开发 主要内容是 面向对象的概念及特性 用面向对象的方式解决简单的标签创建实例 一些基础的 ...

  10. 一个关于C8051F350模拟电源的小问题

    前言 多做重要而不紧急的工作,慢慢的就会发现重要而紧急的工作没那么多了 工作方法 今天有好几个同事出差去现场实验了,为了今天的顺利成行,昨天加了个班,但是从项目管理的角度或者说做事的方法上来讲,这次加 ...