【线段树+归并排序】poj 2104
来源:互联网 发布:阿里云多备案服务号 编辑:程序博客网 时间:2024/05/22 04:29
本题是利用了归并排序的过程,其实归并树就是线段树+归并,只是线段树每个区间里存了这个区间里的有序序列,注意rank的求法,二分答案,求出每个中间值mid在原始序列区间[s,t]里的rank,其中这里面又可以用二分来求mid在[s,t]里排第几,最后相加就是这个rank,比较蛋疼的就是二分时的位置问题,什么时候+1,什么时候-1,很难搞!
每次询问的复杂度O(lgn*lgn*lgn),所以总共为O(m*lgn*lgn*lgn)
ps:归并树原理:
如果对于一段区间,仅查找一次第k大元素的话好说,直接一个快排搞定。
如果有多次离线询问,然后就可以通过归并排序,建一棵归并树(nlogn)对于树的每一个节点,通过归并排序递归的建立一个序列,其中每个节点[l,r]表示原序列中,[l,r]这些数字排序以后的状态。如图,红色节点表示会被分到左子树。
就这样,在区间[l,r]查找第k大元素的时候,先二分枚举元素x,求出x为第几大元素,再在归并树里查找相应区间,对于每一个被包含的区间,二分查找有多少个比当前枚举的元素x小,有多少元素小于等于当前枚举元素x,如果k刚好在这两段区间里,x就是第k大数。程序巨猥琐于是我没写- -!总体复杂度n(logn)^3……强烈膜拜想出此算法的。
这题竟然可以sort水过~震惊了!
#include <vector>#include <list>#include <map>#include <set>#include <queue>#include <string.h>#include <deque>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iostream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <limits.h>using namespace std;int lowbit(int t){return t&(-t);}int countbit(int t){return (t==0)?0:(1+countbit(t&(t-1)));}int gcd(int a,int b){return (b==0)?a:gcd(b,a%b);}#define LL long long#define PI acos(-1.0)#define N 100001#define MAX INT_MAX#define MIN INT_MIN#define eps 1e-8#define FRE freopen("a.txt","r",stdin)int n,m;int mertree[30][N];int a[N];struct node{ int l,r;};node tree[N*3];void Build(int i,int s,int t,int dep){//自下而上建归并树 tree[i].l=s; tree[i].r=t; if(s==t){ mertree[dep][s]=a[s]; return ; } int mid=(s+t)>>1; Build(2*i,s,mid,dep+1); Build(2*i+1,mid+1,t,dep+1); int l=s,r=mid+1; int cnt=s; while(l<=mid && r<=t){ if(mertree[dep+1][l]<mertree[dep+1][r]) mertree[dep][cnt++]=mertree[dep+1][l++]; else mertree[dep][cnt++]=mertree[dep+1][r++]; } if(l==mid+1) while(r<=t) mertree[dep][cnt++]=mertree[dep+1][r++]; else while(l<=mid) mertree[dep][cnt++]=mertree[dep+1][l++];}int solve(int i,int s,int t,int val,int dep){ //O(lgn) if(s<=tree[i].l && t>=tree[i].r){ int l=tree[i].l,r=tree[i].r; int pos=lower_bound(&mertree[dep][l], &mertree[dep][r]+1, val)-&mertree[dep][l];//s,t子区间是已经排好序的,这是也要二分计算当前val在这个子区间里的rank,最后相加就是val在s,t区间里的rank------------O(lgn) return pos; } int res=0; if(s<=tree[2*i].r) res+=solve(2*i,s,t,val,dep+1); if(t>=tree[2*i+1].l) res+=solve(2*i+1,s,t,val,dep+1); return res;}int main(){ while(scanf("%d%d",&n,&m)!=EOF){ int i,j; for(i=1;i<=n;i++)scanf("%d",&a[i]); Build(1,1,n,1); while(m--){ int s,t,rank; scanf("%d%d%d",&s,&t,&rank); rank--;// !!!!! int l=1,r=n,mid; while(l<r){ //O(lgn) mid=(l+r+1)>>1; int tmp=solve(1,s,t,mertree[1][mid],1);//mertree[1]是已经排好序的序列,用二分找出当前要查询的rank if(tmp<=rank)l=mid; else r=mid-1; } printf("%d\n",mertree[1][l]); } } return 0;}
sort~~:
#include <vector>#include <list>#include <map>#include <set>#include <queue>#include <string.h>#include <deque>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iostream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <limits.h>using namespace std;int lowbit(int t){return t&(-t);}int countbit(int t){return (t==0)?0:(1+countbit(t&(t-1)));}int gcd(int a,int b){return (b==0)?a:gcd(b,a%b);}#define LL long long#define PI acos(-1.0)#define N 100001#define MAX INT_MAX#define MIN INT_MIN#define eps 1e-8#define FRE freopen("a.txt","r",stdin)struct node{ int pos; int val;}a[N];bool cmp(node x,node y){ return x.val<y.val;}int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ int i,j,k; for(i=1;i<=n;i++) { scanf("%d",&a[i].val); a[i].pos=i; } sort(a+1,a+n+1,cmp); while(m--){ int s,t,rank; scanf("%d%d%d",&s,&t,&rank); int cnt=0; for(i=1;i<=n;i++){ if(s<=a[i].pos && a[i].pos<=t) cnt++; if(cnt==rank)break; } printf("%d\n",a[i].val); } } return 0;}
- 【线段树+归并排序】poj 2104
- poj 2104 归并树(线段树)
- poj 2299 Ultra-QuickSort 线段树/归并排序
- poj 2299 Ultra-QuickSort 归并排序 线段树
- poj-2299-Ultra-QuickSort(线段树 || 归并排序)
- POJ 2104 归并排序树+二分查找
- poj 2299 Ultra-QuickSort——归并排序求逆序数,线段树离散化
- POJ 2299 Ultra-QuickSort(逆序对数,线段树/树状数组/归并排序)
- POJ 2299 Ultra-QuickSort(归并排序 || 树状数组 || 线段树)
- poj 2299 Ultra-QuickSort 线段树求逆序数+离散化||归并排序求逆序数
- HDU 1394 线段树 || 归并排序
- bzoj 3821 玄学 [线段树+归并排序]
- HDU-1394(线段树|归并排序)
- HDU 4911 Inversion【归并排序||线段树】
- poj 2299 Ultra-QuickSort 【线段树 or 线段树+lazy or 树状数组 or 归并排序】 求逆序对
- poj 2104 归并树
- POJ 2299 归并排序
- POJ 2299 归并排序
- php加水印
- 基数排序(C)
- android各个版本的区别——API变更
- poj--1703/2492 (经典并查集)
- 0x5003eaed错误解决方案
- 【线段树+归并排序】poj 2104
- 争取高分,从第一印象开始---被人忽视的argument开头
- 退一步海阔天空---论argument的段落间让步关系
- 完善论述,向常识靠拢 --- 对Argument段落内other possibilities的思考
- 江畔何人初见月,江月何年初照人?--- Argument中疑问句的用法和误区
- android 面试
- SEE
- VMPlayer安装
- 领略GRE作文思维发散的艺术(by Dincyfeng)