题目第一个坑就是下标是[0,n-1];
问题是:第一个插花的位置和最后一个插花的位置,还有拔了多少花
直接上代码,注释已经很全了
#include #include #include #include #include #include #include #include #include #include using namespace std; const int MAXN = 50010; int n,m; struct Node { int l,r; int sum;//可以插花的位置 int lazy; int first;//第一可以插花的位置 int last;//最后插花的位置 }segTree[MAXN*3];//好像线段树这种题开到3倍就可以,没要4倍。 void pushup(int i) { if(segTree[i].l==segTree[i].r)return;//到叶子节点 segTree[i].sum = segTree[i<<1].sum+segTree[(i<<1)|1].sum; if(segTree[i<<1].first != -1)segTree[i].first = segTree[i<<1].first; else segTree[i].first = segTree[(i<<1)|1].first; if(segTree[(i<<1)|1].last != -1)segTree[i].last = segTree[(i<<1)|1].last; else segTree[i].last = segTree[(i<<1)].last; } void pushdown(int i) { if(segTree[i].r == segTree[i].l) return; if(segTree[i].lazy == 1) { segTree[i<<1].first =segTree[i<<1].l; segTree[i<<1].last = segTree[i<<1].r; segTree[i<<1].sum = segTree[i << 1].r - segTree[i<<1].l+1; segTree[i<<1].lazy = 1; segTree[i<<1|1].first =segTree[i<<1|1].l; segTree[i<<1|1].last = segTree[i<<1|1].r; segTree[i<<1|1].sum = segTree[i << 1|1].r - segTree[i<<1|1].l+1; segTree[i<<1|1].lazy = 1; } if(segTree[i].lazy == -1) { segTree[i<<1].first = segTree[i<<1|1].first = -1; segTree[i<<1].last = segTree[i<<1|1].last = -1; segTree[i<<1].sum = segTree[i<<1|1].sum = 0; segTree[i<<1].lazy = segTree[i<<1|1].lazy = -1; } segTree[i].lazy = 0; } void build(int l,int r,int k) { segTree[k].l = l; segTree[k].r = r; segTree[k].sum = r - l + 1; segTree[k].lazy = 0; segTree[k].first = l; segTree[k].last = r; if(l == r) { return; } int mid = (l + r) /2; build(l,mid,k*2); build(mid+1,r,k*2+1); } int query1(int i,int l,int r) { if(segTree[i].l == l && segTree[i].r == r) { return segTree[i].first; } pushdown(i); int mid = (segTree[i].l + segTree[i].r)/2; int ans1; if(r <= mid)return query1(i<<1,l,r); else if(l > mid)return query1((i<<1)|1,l,r); else { ans1 = query1(i<<1,l,mid); if(ans1 != -1)return ans1; return query1((i<<1)|1,mid+1,r); } } int query2(int l,int r,int k) { if(segTree[k].l == l && segTree[k].r == r) { return segTree[k].last; } pushdown(k); int ans ; int mid = (segTree[k].l+ segTree[k].r) /2; if(r <= mid) return query2(l,r,k*2); else if(l > mid) return query2(l,r,k*2+1); else { ans = query2(mid+1,r,k*2+1); if(ans != -1) { return ans; } else return query2(l,mid,k*2); } } int sum(int i,int l,int r) { if(segTree[i].l == l && segTree[i].r == r) { return segTree[i].sum; } pushdown(i); int mid = (segTree[i].l + segTree[i].r)/2; if(r <= mid)return sum(i<<1,l,r); else if(l > mid)return sum((i<<1)|1,l,r); else return sum((i<<1)|1,mid+1,r)+sum(i<<1,l,mid); } void update(int i,int l,int r,int type) { if(segTree[i].l == l && segTree[i].r==r) { if(type == 0) { if(segTree[i].sum == 0)//* 这个地方要注意 当前范围没有位置可以插花了 就可以不用标记了 是因为如果你标记了 后来如果是另一种操作就会改变此标记 然后传下去 好像实质上是因为范围是空,它的first和last都是-1,也没有我下两行的必要了 { segTree[i].first = -1; segTree[i].last = -1; return; } segTree[i].sum = 0; segTree[i].lazy = -1; segTree[i].first = -1; segTree[i].last = -1; return; } else if(type == 1) { if(segTree[i].sum == segTree[i].r-segTree[i].l+1) { segTree[i].first = segTree[i].l; segTree[i].last = segTree[i].r; return; } segTree[i].sum = segTree[i].r-segTree[i].l+1; segTree[i].lazy = 1; segTree[i].first = segTree[i].l; segTree[i].last = segTree[i].r; return; } } pushdown(i); int mid = (segTree[i].l + segTree[i].r)/2; if(r <= mid)update(i<<1,l,r,type); else if(l > mid)update((i<<1)|1,l,r,type); else { update(i<<1,l,mid,type); update((i<<1)|1,mid+1,r,type); } pushup(i); } int bisearch(int A ,int F) { if(sum(1,A,n) == 0)//如果没有花朵可以插入 那么返回 return -1; if(sum(1,A,n) < F)//如果空余位置多了就可以返回最后一个插入的位置了 return n; int l = A, r =n; int ans = A; while(l<=r)//此处的二分是这道题的精髓,不断二分查找最近右边界,最近! { int mid = (l+r)>>1; if(sum(1,A,mid) >= F) { ans = mid; r = mid -1 ; } else { l = mid + 1; } } return ans; } int main() { int T; cin >> T; while(T--) { cin >> n >> m; build(1,n,1); int op,u,v; while(m--) { cin >> op >> u >> v; if(op==1) { u++; int t = bisearch(u,v); if(t == -1) { cout << "Can not put any one." << endl; continue; } printf("%d %d\n",query1(1,u,t)-1 ,query2(u,t,1)-1); update(1,u,t,0); } else { u++; v++; cout << v-u+1 - sum(1,u,v) <