【解题报告】HDU-4614 Vases and Flowers 线段树+二分

来源:互联网 发布:mac sogo拼音输入法 编辑:程序博客网 时间:2024/06/05 11:21

题目大意:给出n个点从0~n-1排成一条线,然后又m条命令,k=1就是从某个点开始插多少话进去,k=2就是把l到r之间的花扔掉。。换成程序员的语言就是k=1就查询第一个插入点和最后一个插入点,k=2就查询区间插了多少花。

查询差了多少花没什么难度,关键是找第一个和最后一个插入点,显然用二分查找。

#include <iostream>#include <string.h>#include<algorithm>#include <cstdio>using namespace std;#define lc n << 1#define rc n << 1 | 1const int maxn = 50010;struct seg {int l, r, sum;//节点sum存这段区间还有多少空位,或说能插多少花int lazy;}t[maxn << 2];inline int len(int n) { return t[n].r - t[n].l + 1; }inline void push_up(int n){t[n].sum = t[lc].sum + t[rc].sum;}inline void push_down(int n){int x = t[n].lazy;t[lc].sum = (x == 1 ? 0 : len(lc));t[rc].sum = (x == 1 ? 0 : len(rc));t[lc].lazy = t[rc].lazy = x;t[n].lazy = 0;}void build(int n, int l, int r){t[n].l = l;t[n].r = r;t[n].lazy = 0;if (l == r){t[n].sum = 1;return;}int mid = (l + r) >> 1;build(lc, l, mid);build(rc, mid + 1, r);push_up(n);}void update(int n, int l, int r,int a)//a=1是插花,a=-1是扔花{if (l > t[n].r || r < t[n].l)return;if (l <= t[n].l&&r >= t[n].r){t[n].sum = (a == 1 ? 0 : len(n));t[n].lazy = a;return;}if (t[n].lazy)push_down(n);update(lc, l, r, a);update(rc, l, r, a);push_up(n);}int query(int n, int l, int r){if (l > t[n].r || r < t[n].l)return 0;if (l <= t[n].l&&r >= t[n].r)return t[n].sum;if (t[n].lazy != 0)push_down(n);return query(lc, l, r) + query(rc, l, r);}void solve(int l,int r, int f){int x = query(1, l, r);//先查询从l开始一共能插多少花if (x == 0){cout << "Can not put any one." << endl;return;}else if (x < f) { f = x; }//这一步很关键!去除之后会错,原因看二分部分int ql = l, qr = r, mid;while (ql != qr)//找第一个插入点{mid = (ql + qr) >> 1;x = query(1, ql, mid);if (x >= 1)qr = mid;elseql = mid + 1;}cout << ql << ' ';ql = l, qr = r;while (ql != qr)//找最后一个{mid = (ql + qr) >> 1;x = query(1, ql, mid);if (x >= f)//因为这一句话所以f要等于min(f,x){qr = mid;}else{update(1, ql, mid, 1);f -= x;//如果左子树的sum<f那么把左子树插满花ql = mid + 1;}}update(1, qr, qr, 1);//qr这个点可能没更新到printf("%d\n",qr);}int main(){int T, n, m, c, f, b;cin >> T;while (T--){scanf("%d%d",&n,&m);build(1, 0, n - 1); while (m--){scanf("%d%d%d",&c,&b,&f);if (c == 1)solve(b, n - 1, f);else{int q = query(1, b, f);printf("%d\n",(f - b + 1) - q);update(1, b, f, -1);}}printf("\n");}return 0;}