首页 > 代码库 > HDU 4343 Interval query 倍增思想, DP
HDU 4343 Interval query 倍增思想, DP
HDU 4343 Interval query 倍增思想, DP
注意当两个区间只有一个端点重合时,也算是合法的
题目大意:给定N(N<=100000)个区间(左闭右开)和M(M<=100000)个询问[l, r],问所有满足[s,t)包含于于[l, r]的区间中最多能选出多少个,使得他们两两不相交。
解题思路:首先将坐标离散化,将区间排序后删掉可以覆盖其他区间的大区间。
这时若将剩余区间的左端点坐标排序,左端点坐标必然严格上升且对应的右端点坐标也是严格上升的。
此题的贪心思想较为普及,即按y的升序进行贪心固定区间询问的最大数量,不再赘述。
设g[1][x]为从坐标x开始向右遇到的第一个有效区间的右端点坐标,另g[i][x] = g[1][g[i-1][x]],若不存在则为正无穷。
则g[k][x]表示从坐标x开始,在经过不相交的k个区间后,第k个区间的右端点的坐标。
对g进行倍增,即设f[k][x] = g[2^k][x]。则对于一次询问(l,r),可利用f枚举答案各个二进制数位得到答案。
f[k][x] = f[k-1][f[k-1][x]],f[0][x] = g[1][x]。g只存在于思维过程中。
1 #include <bits/stdc++.h> 2 using namespace std ; 3 4 const int N = 100051 ; 5 int n,m,opt[21][N*2],x[N*2] ; 6 int cnt ; 7 struct node 8 { 9 int l,r; 10 void read(){ scanf("%d%d",&l,&r); x[cnt++]=l; x[cnt++]=r; } 11 void print(){ printf("%d %d\n",l,r); } 12 bool operator <(const node tmp) const{ return l<tmp.l||(l==tmp.l&&r<tmp.r); } // 13 }no[N]; 14 15 inline int getid(int val,bool f) 16 // 对于每个 getid l 求出的是 大于等于 l 的 x中最大数 17 // 对于每个 r 求出的是 小于等于 r 的 x中最小数 18 // 以此来确定 询问区间在 x 中的离散后的范围 19 { 20 if(!f) return lower_bound(x,x+cnt,val) - x ; 21 return upper_bound(x,x+cnt,val) - x - 1 ; 22 } 23 24 inline int calc(int l,int r) 25 { 26 if( l > r ) return 0 ; 27 if(l==cnt||r==-1) return 0 ; 28 int ret = 0 ; 29 for(int i=20;i>=0;i--) ///// 30 if(opt[i][l] <=r) { 31 ret+=(1<<i) ; 32 l = opt[ i ][ l ] ; 33 } 34 return ret ; 35 } 36 37 //在算的过程 会将 自己的区间给包含进去 38 int main() 39 { 40 while(~scanf("%d%d",&n,&m)) 41 { 42 cnt = 0 ; 43 for(int i=0;i<n;i++) 44 no[ i ].read() ; 45 sort(no,no+n) ; 46 sort(x,x+cnt) ; 47 cnt = unique(x,x+cnt) - x ; 48 for(int i=0;i<n;i++) 49 { 50 no[ i ].l = getid(no[ i ].l,0) ; 51 no[ i ].r = getid(no[ i ].r,1) ; 52 } 53 x[ cnt ] = cnt ; 54 int mn = cnt , r = n ; 55 for(int i=cnt-1;i>=0;i--) 56 { 57 while(r>0&&no[r-1].l>=i) 58 { 59 r-- ; 60 mn = min(mn,no[ r ].r) ; 61 } 62 opt[0][i] = mn ; // opt[ 0 ][ i ] 表示坐标 i 向右 第一个不冲突 的 区间的右端点的坐标 63 } 64 for(int i=0;i<=20;i++) opt[ i ][cnt] = cnt ; 65 for(int i=1;i<=20;i++) 66 for(int j=0;j<cnt;j++) 67 opt[ i ][ j ] = opt[ i-1 ][ opt[i-1][j] ] ; 68 while(m--) 69 { 70 int l,r ; 71 scanf("%d%d",&l,&r) ; 72 l = getid(l,0) ; 73 r = getid(r,1) ; 74 printf("%d\n",calc(l,r)) ; 75 } 76 } 77 return 0 ; 78 }
HDU 4343 Interval query 倍增思想, DP
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。