• HDU 4614 (13年多校第二场1004)裸线段树


    题意:给你N个花瓶,编号是0  到 N - 1 ,初始状态花瓶是空的,每个花瓶最多插一朵花。

    然后有2个操作。

    操作1,a b c ,往在a位置后面(包括a)插b朵花,输出插入的首位置和末位置。

    操作2,a b ,输出区间[a , b ]范围内的花的数量,然后全部清空。


    很显然这是一道线段树。区间更新,区间求和,这些基本的操作线段树都可以logN的时间范围内完成。

    操作2,很显然就是线段树的区间求和,求出[a , b]范围内的花朵的数量,区间更新,将整个区间全部变成0。

    操作1,这里我们首先需要找出他的首位置和末位置,所以需要二分他的位置。

    首先我们二分他的首位置, l = a , r = n ,在这个区间内二分,找出第一个0的位置,那就是该操作的首位置pos1。

    然后再二分他的末位置,l = pos1 , r = n ,找到第b个0,就是该操作的末位置pos2,然后区间更新[pos1 ,pos2]全部置为1。


    就像解题报告上讲的一样,这是一道很裸的线段树。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <string>
    #include <cmath>
    #include <cstring>
    #include <queue>
    #include <set>
    #include <vector>
    #include <stack>
    #include <map>
    #include <iomanip>
    #define PI acos(-1.0)
    #define Max 2505
    #define inf 1<<28
    #define LL(x) ( x << 1 )
    #define RR(x) ( x << 1 | 1 )
    #define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
    #define ll long long
    #define mem(a,b) memset(a,b,sizeof(a))
    #define mp(a,b) make_pair(a,b)
    #define PII pair<int,int>
    using namespace std;
    #define M 150005
    
    inline void RD(int &ret) {
        char c;
        do {
            c = getchar();
        } while(c < '0' || c > '9') ;
        ret = c - '0';
        while((c=getchar()) >= '0' && c <= '9')
            ret = ret * 10 + ( c - '0' );
    }
    int n , m ;
    int L[M] , R[M] , sum[M] ,add[M] ;
    
    void init(){
        mem(sum ,0) ;
        mem(add, 0) ;
    }
    void push_up(int x){
        sum[x] = sum[LL(x)] + sum[RR(x)] ;
    }
    void push_down(int x){
        if(L[x] == R[x])return ;
        if(add[x] == 1){//全部置为1
            sum[x] = R[x] - L[x] + 1 ;
            sum[LL(x)] = R[LL(x)] - L[LL(x)] + 1 ;
            sum[RR(x)] = R[RR(x)] - L[RR(x)] + 1 ;
            add[LL(x)] = add[x] ;
            add[RR(x)] = add[x] ;
            add[x] = 0 ;
        }
        else if(add[x] == 2){//全部置为0
            sum[x] = 0 ;
            sum[LL(x)] = 0 ;
            sum[RR(x)] = 0 ;
            add[LL(x)] = add[x] ;
            add[RR(x)] = add[x] ;
            add[x] = 0 ;
        }
    }
    void build(int l , int r ,int u){
        L[u] = l ;
        R[u] = r ;
        sum[u] = 0 ;
        add[u] = 0 ;
        if(l == r)return ;
        int mid = l + r >> 1 ;
        build(l , mid ,LL(u)) ;
        build(mid + 1 ,r ,RR(u)) ;
    }
    
    void update(int l ,int r ,int u ,int op){
        if(l > R[u] || r < L[u])return ;
        push_down(u) ;
        if(l == L[u] && r == R[u]) {
            if(op == 1)
                sum[u] = R[u] - L[u] + 1 ;
            else sum[u] = 0 ;
            add[u] = op ;
            return ;
        }
        int mid = L[u] + R[u] >> 1 ;
        if(r <= mid){
            update(l ,r ,LL(u) , op) ;
        }
        else if(l > mid){
            update(l , r , RR(u),op) ;
        }
        else {
            update(l , mid ,LL(u),op) ;
            update(mid + 1  , r , RR(u) ,op) ;
        }
        push_up(u) ;
    }
    int query(int l ,int r ,int u){
        if(l > R[u] || r < L[u])return 0 ;
        push_down(u) ;
        if(l == L[u] && r == R[u]) {
            return sum[u] ;
        }
        int mid = L[u] + R[u] >> 1 ;
        if(r <= mid){
            return query(l , r, LL(u)) ;
        }
        else if(l > mid){
            return query(l , r ,RR(u)) ;
        }
        else {
            return query(l , mid , LL(u)) + query(mid + 1 , r , RR(u)) ;
        }
    }
    void Noanswer(){
        puts("Can not put any one.") ;
    }
    void answer(int p1, int p2){
        printf("%d %d
    ",p1, p2) ;
    }
    void answer(int p){
        printf("%d
    ",p) ;
    }
    void debug(int u){
    
        printf(" 节点 %d 区间 : %d - %d 
    " , u ,L[u] ,R[u]) ;
        printf(" 左子树 %d 右子树 %d 
    " , LL(u) ,RR(u) ) ;
        printf("父节点sum值:%d
    ",sum[u]) ;
        push_down(u) ;
        if(L[u] == R[u])return ;
        debug(LL(u)) ;
        debug(RR(u)) ;
    }
    void solve1(int a , int b){
        int pos1 = inf ;
        int l = a , r = n ;
        int nn = n - a + 1 - query(a , n , 1) ;
        if(!nn){//如果区间内没有0的位置了,那么就直接输出。
            Noanswer() ;
            return ;
        }
        while(r >= l){//二分首位置
            int mid = l + r >> 1 ;
            int now = mid - a + 1 - query(a ,mid ,1) ;
            if(now >= 1){
                pos1 = min(pos1 ,mid) ;
                r = mid - 1 ;
            }
            else l = mid + 1 ;
        }
        int pos2 = inf ;
        nn = n - pos1 + 1 - query(pos1 , n ,1) ;
        if(nn <= b){//如果剩余的0的个数小于等于b的数量,那么需要找出最后一个0的位置。
            int l = pos1 , r = n ;
            while(r >= l){//二分末位置
                int mid = r + l >> 1 ;
                int now = mid - pos1 + 1 - query(pos1 , mid , 1) ;
                if(now == nn){
                    pos2 = min(pos2 , mid) ;
                    r = mid - 1 ;
                }
                else l = mid + 1 ;
            }
            answer(pos1 - 1, pos2 - 1) ;
            update(pos1, pos2 , 1 , 1) ;
        }
        else {//其实我觉得这个二分和上面那个可以合并的,我懒得改了。
            int l = pos1 , r = n ;
    
            while(r >= l){//二分末位置
                int mid = l + r >> 1 ;
                int now = mid - pos1 + 1 - query(pos1, mid, 1) ;
                if(now == b){
                    pos2 = min(pos2 ,mid) ;
                    r = mid - 1 ;
                }
                else if(now > b)r = mid - 1 ;
                else l = mid + 1 ;
            }
            answer(pos1 - 1, pos2 - 1 ) ;
            update(pos1 ,pos2 ,1, 1) ;
        }
    }
    void solve2(int a , int b){
        answer(query(a , b , 1)) ;
        update(a , b, 1 , 2) ;
    }
    int main() {
        int T ;
        cin >> T ;
        int ss = 0 ;
        while( T -- ){
            scanf("%d%d",&n,&m) ;
            init() ;
            build(1 ,n , 1) ;
            while(m -- ){
                //debug(1) ;
                int a , b , c ;
                RD(a) ;
                RD(b) ;
                RD(c) ;
                if(a == 1){
                    b ++ ;
                    solve1(b , c) ;
                }
                else if(a == 2){
                    b ++ , c ++ ;
                    solve2(b , c) ;
                }
            }
            puts("") ;
        }
        return 0 ;
    }
    


  • 相关阅读:
    【Android API】Android 4.1 API官方文档详解
    【Android开发】Android Host详解(翻译自官方文档)
    Android调试桥-Android Debug Birdge详解
    冰淇淋三明治 (Android 4.0)介绍
    Android 4.1的新特性介绍
    【Android UI】如何做一个纯粹的Android app UI 设计
    【Android UI】Android颜色系大全
    【Android开发】交互界面布局详解
    阿里卖电影票 架构思路
    操作系统 虚拟内存 、分段、分页的理解
  • 原文地址:https://www.cnblogs.com/aukle/p/3217597.html
Copyright © 2020-2023  润新知