poj 2761 多种数据结构算法求区间第k大的数
来源:互联网 发布:八零网络验证 编辑:程序博客网 时间:2024/05/17 09:39
Feed the dogs
Time Limit: 6000MS Memory Limit: 65536KTotal Submissions: 15517 Accepted: 4793
Description
Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs every day for Wind. Jiajia loves Wind, but not the dogs, so Jiajia use a special way to feed the dogs. At lunchtime, the dogs will stand on one line, numbered from 1 to n, the leftmost one is 1, the second one is 2, and so on. In each feeding, Jiajia choose an inteval[i,j], select the k-th pretty dog to feed. Of course Jiajia has his own way of deciding the pretty value of each dog. It should be noted that Jiajia do not want to feed any position too much, because it may cause some death of dogs. If so, Wind will be angry and the aftereffect will be serious. Hence any feeding inteval will not contain another completely, though the intervals may intersect with each other.
Your task is to help Jiajia calculate which dog ate the food after each feeding.
Your task is to help Jiajia calculate which dog ate the food after each feeding.
Input
The first line contains n and m, indicates the number of dogs and the number of feedings.
The second line contains n integers, describe the pretty value of each dog from left to right. You should notice that the dog with lower pretty value is prettier.
Each of following m lines contain three integer i,j,k, it means that Jiajia feed the k-th pretty dog in this feeding.
You can assume that n<100001 and m<50001.
The second line contains n integers, describe the pretty value of each dog from left to right. You should notice that the dog with lower pretty value is prettier.
Each of following m lines contain three integer i,j,k, it means that Jiajia feed the k-th pretty dog in this feeding.
You can assume that n<100001 and m<50001.
Output
Output file has m lines. The i-th line should contain the pretty value of the dog who got the food in the i-th feeding.
Sample Input
7 21 5 2 6 3 7 41 5 32 7 1
Sample Output
32
Source
POJ Monthly--2006.02.26,zgl & twb
主席树做法
22108K2266MSC++1406B
#include<stdio.h>#include<algorithm>#include<iostream>#define N 100005#define M N*20using namespace std;struct node{ int x,y,sum;}a[M];int b[N],t[N],root[N],num;void update(int k,int &c,int x,int y){ a[num++]=a[c]; c=num-1; ++a[c].sum; if(x==y) return; int mid=(x+y)>>1; if(k<=mid) update(k,a[c].x,x,mid); else update(k,a[c].y,mid+1,y);}int query(int i,int j,int k,int x,int y){ if(x==y) return x; int p=a[a[j].x].sum-a[a[i].x].sum; int mid=(x+y)>>1; if(k<=p) return query(a[i].x,a[j].x,k,x,mid); else return query(a[i].y,a[j].y,k-p,mid+1,y);}int main(){ int n,m,i,j,k,q,pos; while(scanf("%d%d",&n,&q)!=EOF) { for(i=1;i<=n;i++) { scanf("%d",&b[i]); t[i]=b[i]; } sort(t+1,t+1+n); m=unique(t+1,t+1+n)-t-1;//去重 a[0].x=a[0].y=a[0].sum=0; root[0]=0; num=1; for(i=1;i<=n;i++) { pos=lower_bound(t+1,t+1+m,b[i])-t;//找见位置 root[i]=root[i-1]; //printf("i=%d pos=%d root[i]=%d\n",i,pos,root[i]); update(pos,root[i],1,m); } while(q--) { scanf("%d%d%d",&i,&j,&k); printf("%d\n",t[query(root[i-1],root[j],k,1,m)]); } } return 0;}
线段树做法:
6952K2375MSC++2103B
/*6952K2375MSC++2103B题意:给出每只狗的pretty value,然后多次询问,每次输出区间[i,j](狗站成一排,从第i只到第j只)的第k小的值是多少。注意:区间之间有交叉,但是没有完全包含。分析:先把所有区间排序,然后从左至右把每个区间用线段树维护离散化后的pretty value,即线段树的区间的意义是pretty value。每次删除在上一个区间中且不在当前区间中的节点,插入在当前区间中且不在上一个区间中的节点,使得线段树中的节点恰好为该区间内的所有节点。然后查询第k个就容易了。*/#include<stdio.h>#include<algorithm>#define N 100005using namespace std;int rank[N],ans[N];struct pp{ int l,r,id,k,s;}b[N],c[N];struct node{ int x,y,len;}a[N*3];bool cmp1(pp a,pp b){ return a.l<b.l;}bool cmp2(pp a,pp b){ return a.id<b.id;}int max(int a,int b){ return a>b?a:b;}int min(int a,int b){ return a<b?a:b;}void build(int t,int x,int y){ a[t].x=x; a[t].y=y; a[t].len=0; if(x==y) return ; int mid=(x+y)>>1,temp=t<<1; build(temp,x,mid); build(temp+1,mid+1,y);}void update(int t,int k,int val){ if(a[t].x==a[t].y) { a[t].len+=val; return; } int mid=(a[t].x+a[t].y)>>1,temp=t<<1; if(k<=mid) update(temp,k,val); else update(temp+1,k,val); a[t].len=a[temp].len+a[temp+1].len;}int query(int t,int k){ if(a[t].x==a[t].y) return ans[a[t].x]; int mid=(a[t].x+a[t].y)>>1,temp=t<<1; if(a[temp].len>=k) return query(temp,k); else return query(temp+1,k-a[temp].len);}int main(){ int n,m,i,j; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++) { scanf("%d",&c[i].l); c[i].id=i; } sort(c+1,c+1+n,cmp1); for(i=1;i<=n;i++) { rank[c[i].id]=i; ans[i]=c[i].l; } for(i=1;i<=m;i++) { scanf("%d%d%d",&b[i].l,&b[i].r,&b[i].k); b[i].id=i; } sort(b+1,b+1+m,cmp1); build(1,1,n); for(j=b[1].l;j<=b[1].r;j++) update(1,rank[j],1); b[1].s=query(1,b[1].k); for(i=2;i<=m;i++) { for(j=b[i-1].l;j<=min(b[i-1].r,b[i].l-1);j++)//注意区间的范围 update(1,rank[j],-1); for(j=max(b[i-1].r+1,b[i].l);j<=b[i].r;j++)//注意区间的范围 update(1,rank[j],1); b[i].s=query(1,b[i].k); } sort(b+1,b+1+m,cmp2); for(i=1;i<=m;i++) printf("%d\n",b[i].s); } return 0;}树状数组做法:
4288K1969MSC++1937B
划分树做法:
/*4288K1969MSC++1937B*/#include<stdio.h>#include<string.h>#include<algorithm>#define N 100005using namespace std;struct node{ int x,y,id,k,s;}a[N],b[N];int ans[N],rank[N],c[N];bool cmp(node a,node b){ return a.x<b.x;}bool cmp1(node a,node b){ return a.id<b.id;}int max(int a,int b){return a>b?a:b;}int min(int a,int b){return a<b?a:b;}int lowbix(int x){ return x&(-x);}void update(int x,int num){ while(x<=N) { c[x]+=num; x+=lowbix(x); }}int getsum(int x){ int sum=0; while(x) { sum+=c[x]; x-=lowbix(x); } return sum;}int binary(int k){ int l,r,cnt,an; l=1;r=N; while(l<=r) { int mid=(l+r)>>1; an=getsum(mid); if(an>=k) { r=mid-1; cnt=mid; } else l=mid+1; } return ans[cnt];}int main(){ int n,m,i,j; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++) { scanf("%d",&a[i].x); a[i].id=i; } sort(a+1,a+1+n,cmp); for(i=1;i<=n;i++) { rank[a[i].id]=i; ans[i]=a[i].x; } for(i=1;i<=m;i++) { scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].k); b[i].id=i; } sort(b+1,b+1+m,cmp); memset(c,0,sizeof(c)); for(i=b[1].x;i<=b[1].y;i++) update(rank[i],1); b[1].s=binary(b[1].k); for(i=2;i<=m;i++) { for(j=b[i-1].x;j<=min(b[i-1].y,b[i].x-1);j++) update(rank[j],-1); for(j=max(b[i-1].y+1,b[i].x);j<=b[i].y;j++) update(rank[j],1); b[i].s=binary(b[i].k); } sort(b+1,b+1+m,cmp1); for(i=1;i<=m;i++) printf("%d\n",b[i].s); } return 0;}
划分树做法:
25992K2157MSC++2779B
#include<stdio.h>#include<algorithm>#define N 100100using namespace std;struct node{ int left,right,mid;}a[N*4];struct Tree//tree是记录划分的每一层的结果{ int val;//当前点的值 int num;//区间起点到该点之间有多少个点被移动到了右子区间 int p;//是否被移动到了右子区间}tree[20][N];//注意2^20要大于Nint st[N];void build(int left,int right,int cen,int t){ int m; Tree *last=tree[cen-1],*cur=tree[cen]; //last上一层,cur当前层 a[t].left=left; a[t].right=right; m=a[t].mid=(left+right)>>1; int mid=st[m],sum=0,j,ll=left,rr=m+1; //mid保存的时候区间[left,right]的中值,建树最重要的是处理好重复的中值要放的位置。 //当然,如果数字没有重复是很好做的。 for(j=m;j>=left;j--) { if(st[j]==mid) sum++; else break; } //记录下这个区间的左子区间里面有多少个重复的中值。 //也就是重复的中值有多少个要摆到左子区间去。 for(j=left;j<=right;j++) { int v=last[j].val; if(v==mid) { if(sum)//首先遇到的sum个重复中值摆到左边 { cur[ll++].val=mid; last[j].p=last[j].num=0; sum--; } else { cur[rr++].val=mid; last[j].p=last[j].num=1; } } else if(v<mid) {//小于中值的摆到左子区间,摆的时候维持原来的相对次序 cur[ll++].val=v; last[j].p=last[j].num=0; } else { cur[rr++].val=v; last[j].p=last[j].num=1; } } for(j=left+1;j<=right;j++) { //这样可以累计下从left开始到当前元素中有多少个被移到了右子树中去 last[j].num+=last[j-1].num; } if(left==right) return; int temp=t<<1; build(left,m,cen+1,temp); build(m+1,right,cen+1,temp+1);}int query(int left,int right,int k,int cen,int t){ int mid=a[t].mid; Tree ll=tree[cen][left],rr=tree[cen][right]; if(a[t].left==a[t].right) return ll.val; int dif=(right-left+1)-(rr.num-ll.num+ll.p),temp=t<<1; //dif记录的时候区间[left,right]有多少个去了左子区间,dif=总个数-去右子区间的个数 if(dif>=k) { return query(left-ll.num+ll.p,right-rr.num,k,cen+1,temp); //更新在左子区间查询的是[left-ll.num+ll.p,right-rr.num]里面的第k大值 //(看前面有多少个到了右边) } else { return query(mid+ll.num+1-ll.p,mid+rr.num,k-dif,cen+1,temp+1); //更新右子区间查询[mid+ll.num+1-ll.p,mid+rr.num]里面的第k-dif大值 //(看来了右边的有多少个,加上起点mid) }}int main(){ int n,m,i,j,k; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++) { scanf("%d",&st[i]); tree[0][i].val=st[i]; } sort(st+1,st+1+n); build(1,n,1,1); while(m--) { scanf("%d%d%d",&i,&j,&k); printf("%d\n",query(i,j,k,0,1)); } } return 0;}
0 0
- poj 2761 多种数据结构算法求区间第k大的数
- poj 2761 Feed the dogs 求区间第k大的数
- 【算法】求第k大的数
- poj 2401 划分树 求区间第k大的数
- 算法学习(八)求给定区间的第k小(大)数
- POJ 2761-Feed the dogs(划分树)求区间内第k小的数
- POJ 2104-K-th Number(划分树)求区间内第k小的数
- 【算法题】BFPRT算法:求第K小或者第K大的数
- POJ 2761 Feed the dogs 树状数组求第k大的数
- poj 2104 (求区间第K大元素)
- POJ 1442 Black Box treap求区间第k大
- POJ 2104 (求区间第K大)
- 关于在指定区间求第k小的数,求高效率算法
- 求第K大的数~~
- 求数组第K大的数
- POJ 2761 Feed the dogs 求区间第k大 划分树
- 可持久化线段树|主席树 POJ 2104 区间第k大的数
- 求m个区间中第k小的数
- 好的 2012 素数判定
- 基于Zepto的Alert提示框开源框架Tiny-Alert
- SQL Server 开发利器 SQL Prompt 5.3.4.1 Edition T-SQL智能感知分析器 完全破解+使用教程
- 自考——数据库系统原理(浏览)
- 对于Mahout_“推荐算法”的初步认识(1)
- poj 2761 多种数据结构算法求区间第k大的数
- Android中将汉字转换成拼音
- lua调用C函数
- Hook MessageBox 进阶 跨进程Hook
- C语言中extern的用法
- 平衡二叉树(解惑)
- hdu-1114-Piggy-Bank
- NYOJ513,A+B Problem IV
- NYOJ21 【三个水杯】