题意:给你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 ; }