HDU-4614 Vases and Flowers(线段树+区间修改+二分)
2017-09-03 21:37
447 查看
题目链接:
HDU - 4614题目大意:
有n个花瓶,标号0 ~ n−1。m个操作,‘1AF′,表示从A位置开始插F朵花,遇到有花的花瓶跳过。到最后一个花瓶都还有花剩余,丢弃剩下的花。
‘2AB′,表示将区间[A,B]内的花瓶全部清空。(A≤B)
对于每个1操作,输出第一个和最后一个插花的位置,如果一朵花都插不了,输出‘Can not put any one.’;对于每个2操作,输出区间[A,B]内被清空的花瓶的数量。
数据范围:
1<n<50011<m<5001解题思路:
看到网上方法很多,我觉得存区间内的空花瓶数量比较简单。原来标号0 ~ n−1,但我更习惯1 ~ n。令num(i,j)为区间[i,j]的空花瓶数。
对于一个1操作,首先判一下num(A,n)是否大于0。之后,因为区间[A,n]的空花瓶数是单调不递减的,所以可以通过二分查找到 一个最小的位置L,使得num(A,L)==1,则此时的L就是第一个插花的位置;同样二分找到一个最小的位置R,使得num(A,R)==min(F,num(A,n)),则此时的R就是最后一个插花的位置。(输出时记得减1)
对于一个2操作,那就简单了嘛!直接询问区间[A,B]的空花瓶数,拿总数一减,输出完事。
详见代码:
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <set> #include <map> #include <queue> #include <stack> using namespace std; typedef long long LL; const int inf = 1 << 30; const LL INF = 1LL << 60; const int MaxN = 50005; int T, n, m; struct segtree { int l, r; int sum; //区间内空瓶的数量 }tree[4 * MaxN + 5]; int lazy[4 * MaxN + 5]; //lazy[rt]为1时表示rt所管辖的区间内的花瓶全空,为0则表示全满 void push_up(int rt) { tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum; } void Build(int rt, int l, int r) { tree[rt].l = l, tree[rt].r = r; tree[rt].sum = r - l + 1; lazy[rt] = -1; if(l == r) return; int mid = (l + r) >> 1; Build(rt << 1, l, mid); Build(rt << 1 | 1, mid + 1, r); push_up(rt); } void push_down(int rt) { if(lazy[rt] != -1) { lazy[rt << 1] = lazy[rt]; lazy[rt << 1 | 1] = lazy[rt]; int mid = (tree[rt].l + tree[rt].r) >> 1; //将信息传给左右儿子 tree[rt << 1].sum = (mid - tree[rt].l + 1) * lazy[rt]; tree[rt << 1 | 1].sum = (tree[rt].r - mid) * lazy[rt]; lazy[rt] = -1; //标记清空 } } void update(int rt, int L, int R, int c) { if(L <= tree[rt].l && tree[rt].r <= R) { tree[rt].sum = (tree[rt].r - tree[rt].l + 1) * c; lazy[rt] = c; //标记当前区间 return; } if(tree[rt].l == tree[rt].r) return; push_down(rt); //下放标记 int mid = (tree[rt].l + tree[rt].r) >> 1; if(L <= mid) update(rt << 1, L, R, c); if(R > mid) update(rt << 1 | 1, L, R, c); push_up(rt); } int query(int rt, int L, int R) { //得到区间[L, R]中的空花瓶数 if(R < tree[rt].l || tree[rt].r < L) return 0; if(L <= tree[rt].l && tree[rt].r <= R) return tree[rt].sum; push_down(rt); int mid = (tree[rt].l + tree[rt].r) >> 1; int res = 0; if(L <= mid) res += query(rt << 1, L, R); if(R > mid) res += query(rt << 1 | 1, L, R); return res; } //这个二分在这道题里算是比较关键的,作用是查找第num个空花瓶的位置 int bin_search(int x, int num) { int l = x, r = n; int mid = 0, ans = 0; while(l <= r) { mid = (l + r) >> 1; if(query(1, x, mid) >= num) ans = mid, r = mid - 1; else l = mid + 1; } return ans; } int main() { scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); Build(1, 1, n); for(int i = 1; i <= m; i++) { int op; scanf("%d", &op); if(op == 1) { int A, F; scanf("%d %d", &A, &F); A++; int cnt = query(1, A, n); //得到区间[A, n]中的空花瓶数 if(cnt == 0) printf("Can not put any one.\n"); else { int L = bin_search(A, 1); //二分左端点(第1个能插花的位置) int R = bin_search(A, min(cnt, F)); //二分右端点(最后一个能插花的位置) //printf("L = %d R = %d\n", L, R); update(1, L, R, 0); //将区间[L, R]的花瓶全部插满 printf("%d %d\n", L - 1, R - 1); } } else if(op == 2) { int L, R; scanf("%d %d", &L, &R); L++; R++; printf("%d\n", R - L + 1 - query(1, L, R)); update(1, L, R, 1); //将区间[L, R]的花瓶全部清空 } } printf("\n"); } return 0; }
相关文章推荐
- HDU - 4614 Vases and Flowers(线段树 区间修改 二分)
- HDU 4614 Vases and Flowers(线段树区间更新+二分)
- hdu 4614 Vases and Flowers(线段树区间更新+二分)
- HDU 4614 Vases and Flowers (二分查找+线段树区间更新)
- hdu-4614-Vases and Flowers(线段树,区间更新区间查询,lazy,二分)
- HDU 4614 Vases and Flowers (线段树[区间赋值+区间求和] + 二分)
- HDU-4614 Vases and Flowers (线段树区间更新)
- Hdu 4614 Vases and Flowers【二分+线段树】
- 【线段树维护区间编号 && 区间更新】HDU - 4614 Vases and Flowers
- HDU 4614 Vases and Flowers(线段树、二分)
- hdu 4614 Vases and Flowers (二分 线段树)
- Vases and Flowers HDU - 4614(线段树区间更新)
- HDU 4614-Vases and Flowers(线段树区间更新)
- HDU 4614 Vases and Flowers 线段树 + 二分
- HDU 4614 Vases and Flowers [二分 + 线段树]
- HDU 4614 Vases and Flowers (线段树 + 二分)
- HDU 4614 Vases and Flowers [二分 + 线段树]
- hdu 4614 Vases and Flowers (二分 线段树)
- HDU-4614 Vases and Flowers 线段树区间更新
- hdu 4614 Vases and Flowers(线段树加二分查找)