CC Sereja and Ballons (主席树)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题意:有n个盒子,每个盒子有若干个气球,每次操作可以拿走某个盒子的一个气球,然后 给出一些区间,问每次操作后有多少个区间的盒子全为空。

http://www.codechef.com/AUG13/problems/SEABAL

做法:用链表维护一下当前位置前一个非0位置,下一个非0位置。

如果当前位置为k,前一个非0位置为l,下一个非0位置为r。

那么当前位置减为了0,此时增加的区间应该是左端点在(l,k] ,右端点在[k,r)。

那么接下来就是查询一下有多少个区间满足这个条件。

用主席树维护以每个位置为区间右端点的左端点位置。

 

#include <iostream>

#include <cstdio>

#include <set>

#include <vector>

#include <cstring>

#include <algorithm>

#define mem(a,b) memset (a , b , sizeof(a))

using namespace std;

const int N = 100005;

const int M = 30000005;

struct Node {

    int l , r;

    void input () {

        scanf ("%d %d" , &l , &r);

    }

    bool operator < (const Node &n) const {

        return r < n.r;

    }

}que[N];

int n , m , q , a[N]; 

int T[M] , lson[M] , rson[M] , sum[M] , tot = 0;

int l[N] , r[N];

int bulid (int l , int r) {

    int root = ++ tot;

    sum[root] = 0;

    if (l != r) {

        int m = (l + r) >> 1;

        lson[root] = bulid (l , m);

        rson[root] = bulid (m + 1 , r);

    }

    return root;

}

int update (int root , int l , int r , int pos) {

    int newroot = ++ tot;

    sum[newroot] = sum[root] + 1;

    if (l != r) {

        int m = (l + r) >> 1;

        if (pos <= m) {

            lson[newroot] = update (lson[root] , l , m , pos);

            rson[newroot] = rson[root];

        }

        else {

            rson[newroot] = update (rson[root] , m + 1 , r , pos);

            lson[newroot] = lson[root];

        }

    }

    //cout << sum[newroot] << " " << sum[lson[newroot]] << " " << sum[rson[newroot]] << endl;;

    return newroot;

}

int query (int root , int L , int R , int l , int r) {

    if (L == l && R == r) {

        return sum[root];

    }

    int m = (L + R) >> 1;

    if (r <= m) return query (lson[root] , L , m , l , r);

    else if (l > m) return query (rson[root] , m + 1 , R , l , r);

    else return query (lson[root] , L , m , l , m) + query (rson[root] , m + 1 , R , m + 1 , r);

}

void out (int root , int l , int r) {

    cout << l << " " << r << " " << sum[root] << endl;

    if (l != r) {

        int m = (l + r) >> 1;

        out (lson[root] , l , m);

        out (rson[root] , m + 1 , r);

    }

}

int main () {

    // freopen ("input.txt" , "r" , stdin);

    // freopen ("output.txt" , "w" , stdout);

    scanf ("%d %d" , &n , &m);

    l[0] = 0; r[n + 1] = n + 1;

    for (int i = 1 ; i <= n ; i ++) {

        scanf ("%d" , &a[i]);

        l[i] = i - 1;

        r[i] = i + 1;

    }

    for (int i = 0 ; i < m ; i ++) {

        que[i].input();

    }

    sort (que , que + m);

    T[0] = bulid (1 , n);

    for (int i = 1 , j = 0 ; i <= n ; i ++) {

        T[i] = T[i - 1];

        while (j < m && que[j].r == i) {

            T[i] = update (T[i] , 1 , n , que[j].l);

            j ++;

        }

        // cout << "root : " << i << endl;

        // out (T[i] , 1 , n);

    }

    scanf ("%d" , &q);

    int ans = 0;

    while (q --) {

        int k;

        scanf ("%d" , &k);

        k += ans;

        //cout << k << endl;

        a[k] --;

        if (a[k] == 0) {

            int L = l[k] , R = r[k];

            int ret = query (T[R - 1] , 1 , n , L + 1 , k) - query (T[k - 1] , 1 , n , L + 1 , k); 

            ans += ret;

            // cout << "ret :" << ret << endl;

            if (r[k] <= n) l[r[k]] = l[k];  

            if (l[k] >= 1) r[l[k]] = r[k];

        }

        printf ("%d\n" , ans);                

    }

    return 0;

}


 

 

你可能感兴趣的:(on)