1129 - 喵哈哈村的战斗魔法师丶坏坏い月 线段树
2017-08-09 19:07
357 查看
题意:n个数,有q次询问,每次询问有两个操作 1.在区间【l, r】找到比v大的第一个数的下标 2.把【l,r】的数全部加上v。
思路: 裸线段树的题
写法1:线段树
写法二:分块
思路: 裸线段树的题
写法1:线段树
#include <cstdio> #include <cstring> #include <iostream> #define mem(a) memset(a, 0, sizeof(a)) using namespace std; const int inf = 0x3f3f3f3f; const int MAXN =100100; typedef long long LL; LL a[MAXN]; LL lazy[MAXN<<2]; struct T { int l, r; LL m; } tree[MAXN<<2]; void pushdown(int k) { if(lazy[k]) { tree[k<<1].m+=lazy[k]; tree[k<<1|1].m+=lazy[k]; lazy[k<<1]+=lazy[k]; lazy[k<<1|1]+=lazy[k]; lazy[k]=0; } return ; } void pushup(int k) { tree[k].m=max(tree[k<<1].m, tree[k<<1|1].m); } void build(int l, int r, int k) { tree[k].l=l; tree[k].r=r; tree[k].m=0; if(l==r) { tree[k].m=a[l]; return; } int mid = (l+r)>>1; build(l, mid, k<<1); build(mid+1, r, k<<1|1); pushup(k); } void update(int l, int r, int k, LL w) { if(tree[k].l>=l&&tree[k].r<=r) { tree[k].m+=w; lazy[k]+=w; return; } pushdown(k); int mid = (tree[k].l+tree[k].r)>>1; // if(l<=mid) // update(l, r, k<<1, w); // if(r>mid) // update(l, r, k<<1|1, w); //两种写法都可以。 if(l>mid) update(l, r, k<<1|1, w); else if(r<=mid) update(l,r,k<<1,w); else { update(l, mid, k<<1, w); update(mid+1, r, k<<1|1, w); } pushup(k); return ; } int query(int l, int r, int k, LL c) { if(tree[k].m<c) return -1; if(tree[k].l==tree[k].r) return tree[k].l; pushdown(k); pushup(k); int mid = (tree[k].l+tree[k].r)>>1; int x=-1, y=-1; if(l<=mid) x=query(l, r, k<<1, c); if(x!=-1)return x; if(r>mid) y=query(l, r, k<<1|1, c); return y; } int main() { int t, q; scanf("%d",&t); while(t--) { int n; memset(lazy, 0, sizeof(lazy)); scanf("%d %d",&n, &q); for(int i=1; i<=n; ++i) scanf("%lld", &a[i]); build(1, n, 1); int op, l, r; LL v; while(q--) { scanf("%d %d %d %lld", &op, &l,&r, &v); if(op==1) printf("%d\n", query(l, r, 1, v)); else update(l, r, 1, v); } } return 0; }
写法二:分块
#include <bits/stdc++.h> using namespace std; const int MAXN = 100005; typedef long long LL; LL a[MAXN], b[MAXN]; LL add[MAXN], mx[MAXN]; int n, block; void init() { block = sqrt(n); int num = n/block; for(int i=1; i<=num; ++i) for(int j=(i-1)*block+1; j<=i*block; ++j) mx[i]=max(a[j], mx[i]);//维护每一块的最大值 if(n%num) num++;//如果不湿刚好分完块 for(int i=num; i<=num; ++i) for(int j=(num-1)*block+1; j<=n; ++j) mx[i]=max(a[j],mx[i]);//对最后一块找最大 // for(int i=1;i<=num;++i) // printf("%lld\n", mx[i]); for(int i=1; i<=n; ++i) b[i]=(i-1)/block+1;//标记下标i在第几块 } void update(int l,int r,LL k) { int lq=b[l]; int rq=b[r]; //printf("%d %d\n", b[l], b[r]); if(lq==rq)//如果在同一块, 暴力sqrt(n)更新 { for(int i=l; i<=r; i++) { a[i]+=k; if(a[i]+add[lq]>mx[lq]) mx[lq]=a[i]+add[lq]; } return ; } for(int i=l; i<=lq*block; i++) { a[i]+=k; if(a[i]+add[lq]>mx[lq]) mx[lq]=a[i]+add[lq]; } for(int i=(rq-1)*block+1; i<=r; i++) { a[i]+=k; if(a[i]+add[rq]>mx[rq]) mx[rq]=a[i]+add[rq]; } //如果区间跨度大于两块,也就是r-l>1,直接更新块(分块的核心) if(rq-lq>1) { for(int i=lq+1; i<rq; i++) { add[i]+=k; mx[i]+=k; } } } LL query(int l,int r,LL k) { int lq=b[l]; int rq=b[r]; if(lq==rq)//只有一块 { for(int i=l; i<=r; i++) { if(a[i]+add[lq]>=k) return i; } return -1; } //从左向右找,找到直接返回下标 for(int i=l; i<=lq*block; i++) { if(a[i]+add[lq]>=k) return i; } if(rq-lq>1)//有多块 { for(int i=lq+1; i<rq; i++) { if(mx[i]>=k) { for(int j=(i-1)*block+1; j<=i*block; j++) { if(a[j]+add[i]>=k) return j; } } } } for(int i=(rq-1)*block+1; i<=r; i++) { if(a[i]+add[rq]>=k) return i; } return -1; } int main() { int t; scanf("%d", &t); while(t--) { int q; memset(add, 0, sizeof(add)); memset(mx, 0, sizeof(mx)); scanf("%d %d", &n, &q); for(int i=1; i<=n; ++i) scanf("%lld", &a[i]); init(); while(q--) { int op, l,r; LL k; scanf("%d%d%d%lld",&op,&l,&r,&k); if(op==1) printf("%lld\n",query(l,r,k)); else { update(l,r,k); // for(int i=1;i<=n;++i) // printf("%lld%c", a[i]+add[b[i]], " \n"[i==n]); } } } return 0; }
相关文章推荐
- 玲珑学院OJ 1129 喵哈哈村的战斗魔法师丶坏坏い月【线段树查询最左端大于某个数的操作】
- 玲珑学院1129 - 喵哈哈村的战斗魔法师丶坏坏い月(线段树)
- ifrog 1129 喵哈哈村的战斗魔法师丶坏坏い月 线段树||分块
- 1129 - 喵哈哈村的战斗魔法师丶坏坏い月(线段树)@
- LonLife-ACM 1129 - 喵哈哈村的战斗魔法师丶坏坏い月
- 玲珑学院1129 - 喵哈哈村的战斗魔法师丶坏坏い月(分块)
- 玲珑杯1129-喵哈哈村的战斗魔法师丶坏坏い月
- 玲珑OJ 1129 - 喵哈哈村的战斗魔法师丶坏坏い月
- “玲珑杯”线上赛 Round #15 河南专场 H -- 喵哈哈村的战斗魔法师丶坏坏い月 分块/线段树
- 1129 - 喵哈哈村的战斗魔法师丶坏坏い月(河南专场)
- 玲珑学院OJ 1129 喵哈哈村的战斗魔法师丶坏坏い月【暴力分块】
- 喵哈哈村的魔法考试 Round #2 (Div.2) B.喵哈哈村的种花魔法 线段树 区间更新 单点查询
- 喵哈哈村的冒菜店-(线段树的区间合并)
- 喵哈哈村的冒菜店(线段树 区间合并)
- 喵哈哈村的种花魔法(线段树(区间更新,单点查询),前缀和(单点更新,区间查询))
- qscoj:喵哈哈村的冒菜店(线段树区间合并)
- POJ 2528 Mayor's posters(离散化加线段树成段更新)
- codevs 1299 线段树 区间更新查询
- 数据结构之线段树
- [最短路 Bfs 二维线段树] JOI Open Contest 2017 Golf