1. 从a开始在空花瓶放b枝花,花放完或第N-1个花瓶放完为止 输出放花的第一个和最后一个位置
2. 将[a,b]的花都扔掉 输出扔了多少枝花
思路:
线段树维护[0,N-1]空花瓶数v
求a之前有多少空花瓶V(查[0,N-1]空花瓶数 - [a,N-1]空花瓶数)
二分查找放花的第一个和最后一个位置(
先求出可以放多少枝花,min ( [a,N-1]的空花瓶数 , b )
然后
二分查找第V+1个空瓶的位置 是第一个放花的位置
二分查找第V+b个空瓶的位置 是最后一个放花的位置)
因为维护的是区间空花瓶数的和 从[0,N-1]是递增的 仔细体会!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lson (pos<<1)
#define rson (pos<<1|1)
const int maxn=55555;
struct Node{
int l,r;
int v,col;//v 空花瓶数, col lazy标记
}node[maxn<<2];
int N,M;
void pushup(int pos){
node[pos].v=node[lson].v+node[rson].v;
}
void pushdown(int pos){
if(node[pos].col>=0){//有被标记
node[lson].col=node[pos].col; node[rson].col=node[pos].col;
node[lson].v=(node[lson].r-node[lson].l+1)*node[pos].col;
node[rson].v=(node[rson].r-node[rson].l+1)*node[pos].col;
node[pos].col=-1;
}
}
void Build(int L,int R,int pos){
node[pos].l=L; node[pos].r=R; node[pos].col=-1;//初始化
if(L==R){ node[pos].v=1; return;}//叶子 递归边界
int m=(L+R)>>1;
Build(L,m,lson); Build(m+1,R,rson); pushup(pos);//回溯前由现在的节点更新父节点
}
void UpDate(int L,int R,int pos,int value){
if(L <= node[pos].l && node[pos].r <= R){
node[pos].v = (node[pos].r - node[pos].l + 1) * value;
node[pos].col = value;
return;
}
pushdown(pos);
int m = (node[pos].l + node[pos].r) >> 1;
if(L<=m) UpDate(L,R,lson,value);
if(R>m) UpDate(L,R,rson,value);
pushup(pos);
}
int Query_sum(int L,int R,int pos){//空花瓶数
if(L<=node[pos].l&&node[pos].r<=R) return node[pos].v;
pushdown(pos);//递归前下推标记
int m=(node[pos].l+node[pos].r)>>1;
int ret=0;
if(L<=m) ret+=Query_sum(L,R,lson); //都是L、R
if(R>m) ret+=Query_sum(L,R,rson);
pushup(pos);
return ret;
}
void Search(int value,int pos,int &p){
if(node[pos].l==node[pos].r){ p=node[pos].l; return; }
pushdown(pos);
int m=(node[pos].l+node[pos].r)>>1;
if(node[lson].v>=value) Search(value,lson,p);
else Search(value-node[lson].v,rson,p);
pushup(pos);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&N,&M);
Build(0,N-1,1);
int op,a,b;
for(int i=0;i<M;++i){
scanf("%d%d%d",&op,&a,&b);
if(op==1){//修改 放花
int sum=Query_sum(0,N-1,1);
int k1=Query_sum(a,N - 1,1);//[a,N-1]一共有k1个空花瓶
int v=sum-k1;//a之前有v个空花瓶 修改操作起:第v+1个空花瓶
int p,q;
if(k1==0){ printf("Can not put any one.\n"); continue;}
if(k1 < b) b = k1;//空花瓶数k1不足b个 则最多只能插k1朵花
Search(v + 1,1,p);//查第v+1个空花瓶在哪
Search(v + b,1,q);//查第v+b个空花瓶在哪 (修改操作止:第v+b个空花瓶 )
UpDate(p,q,1,0);//区间[p,q]改为0(空花瓶1 非空为0)
printf("%d %d\n",p,q);
} else if(op == 2){
int value = Query_sum(a,b,1);//查[a,b]区间空花瓶数
UpDate(a,b,1,1);//区间[p,q]改为0(空花瓶1 非空为0)
printf("%d\n",b - a + 1 - value);
}
}
printf("\n");
}
return 0;
}