zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",calc(l,r)) ; 
    75         }
    76     }
    77     return 0 ; 
    78 }
  • 相关阅读:
    day60----日考
    css之单位
    如何装双系统win10下装Ubuntu
    css之Grid Layout详解
    css之position详解
    html+css的用户注册界面
    self-introduction
    ps常用操作
    前端基础之BOM和DOM
    emment语法
  • 原文地址:https://www.cnblogs.com/third2333/p/7132042.html
Copyright © 2011-2022 走看看