【线段树合并】bzoj3545: [ONTAK2010]Peaks
1A还行
Description
在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
Input
第一行三个数N,M,Q。
第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。
Output
对于每组询问,输出一个整数表示答案。
HINT
【数据范围】
N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。
题目分析
题目所求的是“小于等于x的边”所成连通块中的第k大,这里就会自然想到处理这一类连通块问题的策略:从小到大加边维护连通块,并在这个过程中离线处理查询。
现在要维护的连通块信息是无序的集合,于是第一反应就是用set合并。但是显而易见的是,set不能处理第k大问题(话说暑假做“不等式组”那题时候第一反应就是用multiset处理,但是当时被查询key和第k大困扰了很久)。有一种常见的方法是采用权值线段树实现set的功能,这样一来就可以处理一些基础的查询问题。
处理完了连通块和维护的操作,接下去的问题就是合并。权值线段树本质上还是线段树,所以使用线段树合并的套路就可以保证这一部分的复杂度。
感觉是比较套路和数据结构的题,好像没什么营养……
- #include<bits/stdc++.h>
- const int maxn = ;
- const int maxq = ;
- const int maxm = ;
- const int maxNode = ;
- struct node
- {
- int l,r,val;
- }a[maxNode];
- struct QRs
- {
- int v,x,k,id;
- bool operator < (QRs a) const
- {
- return x < a.x;
- }
- }qr[maxq];
- struct Edge
- {
- int u,v,val;
- Edge(int a=, int b=, int c=):u(a),v(b),val(c) {}
- bool operator < (Edge a) const
- {
- return val < a.val;
- }
- }edges[maxm];
- int n,m,q,dal,tot,ans[maxq];
- int fat[maxn],h[maxn],cnt[maxn],rt[maxn];
- int read()
- {
- char ch = getchar();
- int num = , fl = ;
- for (; !isdigit(ch); ch=getchar())
- if (ch=='-') fl = -;
- for (; isdigit(ch); ch=getchar())
- num = (num<<)+(num<<)+ch-;
- return num*fl;
- }
- int find(int x){return x==fat[x]?x:fat[x]=find(fat[x]);}
- int query(int rt, int l, int r, int c)
- {
- if (l==r) return l;
- int mid = (l+r)>>;
- if (c <= a[a[rt].l].val)
- return query(a[rt].l, l, mid, c);
- return query(a[rt].r, mid+, r, c-a[a[rt].l].val);
- }
- int queryPos(int v, int k)
- {
- int anc = find(v);
- if (a[rt[anc]].val < k) return -;
- return cnt[query(rt[anc], , cnt[], a[rt[anc]].val-k+)];
- }
- void update(int &rt, int l, int r, int c)
- {
- if (!rt) rt = ++tot;
- ++a[rt].val;
- if (l==r) return;
- int mid = (l+r)>>;
- if (c <= mid) update(a[rt].l, l, mid, c);
- else update(a[rt].r, mid+, r, c);
- }
- void merge(int &u, int v)
- {
- if (u*v==){
- u = u?u:v;
- return;
- }
- a[u].val += a[v].val;
- merge(a[u].l, a[v].l);
- merge(a[u].r, a[v].r);
- }
- int main()
- {
- n = read(), m = read(), q = read();
- for (int i=; i<=n; i++) h[i] = cnt[i] = read(), fat[i] = i;
- for (int i=; i<=m; i++)
- edges[i].u = read(), edges[i].v = read(), edges[i].val = read();
- for (int i=; i<=q; i++)
- qr[i].v = read(), qr[i].x = read(), qr[i].k = read(), qr[i].id = i;
- std::sort(edges+, edges+m+);
- std::sort(cnt+, cnt+n+);
- std::sort(qr+, qr+q+);
- cnt[] = std::unique(cnt+, cnt+n+)-cnt-;
- for (int i=; i<=n; i++)
- {
- h[i] = std::lower_bound(cnt+, cnt+cnt[]+, h[i])-cnt;
- update(rt[i], , cnt[], h[i]);
- }
- dal = ;
- for (int i=; i<=m; i++)
- {
- int fu = find(edges[i].u), fv = find(edges[i].v);
- if (fu!=fv){
- for (; dal<=q&&qr[dal].x < edges[i].val; ++dal)
- ans[qr[dal].id] = queryPos(qr[dal].v, qr[dal].k);
- fat[fu] = fv, merge(rt[fv], rt[fu]);
- }
- }
- for (int i=dal; i<=q; i++)
- ans[qr[i].id] = queryPos(qr[i].v, qr[i].k);
- for (int i=; i<=q; i++) printf("%d\n",ans[i]);
- return ;
- }
END
【线段树合并】bzoj3545: [ONTAK2010]Peaks的更多相关文章
- 【bzoj3545】[ONTAK2010]Peaks 线段树合并
[bzoj3545][ONTAK2010]Peaks 2014年8月26日3,1512 Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路 ...
- [BZOJ3545] [ONTAK2010]Peaks(线段树合并 + 离散化)
传送门 由于困难值小于等于x这个很恶心,可以离线处理,将边权,和询问时的x排序. 每到一个询问的时候,将边权小于等于x的都合并起来再询问. .. 有重复元素的线段树合并的时间复杂度是nlog^2n # ...
- BZOJ.3545.[ONTAK2010]Peaks(线段树合并)
题目链接 \(Description\) 有n个座山,其高度为hi.有m条带权双向边连接某些山.多次询问,每次询问从v出发 只经过边权<=x的边 所能到达的山中,第K高的是多少. \(Solut ...
- BZOJ3545 Peaks 离线处理+线段树合并
题意: 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经 ...
- bzoj3545 Peaks 线段树合并
离线乱搞... 也就是一个线段树合并没什么 #include<algorithm> #include<iostream> #include<cstring> #in ...
- bzoj3545: [ONTAK2010]Peaks 重构树 主席树
题目链接 bzoj3545: [ONTAK2010]Peaks 题解 套路重构树上主席树 代码 #include<cstdio> #include<algorithm> #de ...
- Peaks 线段树合并
Peaks 线段树合并 \(n\)个带权值\(h_i\)山峰,有\(m\)条山峰间双向道路,\(q\)组询问,问从\(v_i\)开始只经过\(h_i\le x\)的路径所能到达的山峰中第\(k\)高的 ...
- 线段树合并&&启发式合并笔记
这俩东西听起来很高端,实际上很好写,应用也很多~ 线段树合并 线段树合并,顾名思义,就是建立一棵新的线段树保存原有的两颗线段树的信息. 考虑如何合并,对于一个结点,如果两颗线段树都有此位置的结点,则直 ...
- bzoj3545 [ONTAK2010]Peaks、bzoj3551 [ONTAK2010]Peaks加强版
题目描述: bzoj3545,luogu bzoj3551 题解: 重构树+线段树合并. 可以算是板子了吧. 代码(非强制在线): #include<cstdio> #include< ...
随机推荐
- 一个线性表中的元素为整数,设计一个算法,将正整数和负整数分开,使线性表的前一半为负整数,后一半为正整数。(C语言)
以下为完整可运行示例代码: #include <stdio.h> #include <stdlib.h> typedef struct LNode{ int data; str ...
- 服务器安装docker后免除sudo命令
1. 先建立一个docker组:sudo groupadd docker 2. 将用户加入docker组:sudo usermod -aG docker (用户名) 3. 先退出登录:exit 4. ...
- hls流媒体视频防盗实现
HLS流媒体视频防盗实现 一.Windows安装FFmpeg 1.1 安装版本 1.1.1 网址:https://ffmpeg.org/ 1.1.2 选择Windows版本:https://ffmpe ...
- BZOJ 1433 && Luogu P2055 [ZJOI2009]假期的宿舍 匈牙利算法
刚学了匈牙利正好练练手(我不会说一开始我写错了)(怕不是寒假就讲了可是我不会) 把人看做左部点,床看作右部点 建图:(!!在校相当于有床,不在校相当于没有床 但是要来学校) 1.在校的 不走的人 自己 ...
- 2、linux基础知识与技能
2.1.linux内核.发行版linux本身指的是一个操作系统内核,只有内核是无法直接使用的.我们需要的,可以使用的操作系统是一个包含了内核和一批有用的应用程序的一个集合体,这个就叫linux发行版. ...
- 开源组件 Mark
http://www.cnblogs.com/asxinyu/category/661170.html
- Unity3d网格合并
几个不同的物体,在Unity3d中可以将网格合并在一起,用于优化. 在Unity3d中构建临时场景如下:建一C#脚本名为"CombineMeshes",挂在Cube上. Combi ...
- SQL函数TIMEDIFF在Java程序中使用报错的问题分析
需求背景 (读者可略过)司机每天从早到晚都会去到不同的自动售货机上补货,而且补货次数和路线等也是因人而异,补货依据是由系统优化并指派.但是目前系统还无法实施有效指挥和优良的补货策略,司机的补货活动因此 ...
- 多线程(Thread、线程创建、线程池)
第1章 多线程 1.1 多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程 ...
- Mac、Linux下两个Emacs共享一个配置文件
Mac.Linux下两个Emacs共享一个配置文件 有些嵌入式的实验需要在Linux进行,就安装了RHEL6.4的虚拟机,下载并编译了Emacs. 在Linux的.emacs文件中加入以下语句,即可引 ...