CDOJ 1292 卿学姐种花 暴力 分块 线段树
2016-03-24 19:51
369 查看
卿学姐种花
题目连接:
http://acm.uestc.edu.cn/#/problem/show/1292Description
众所周知,在喵哈哈村,有一个温柔善良的卿学姐。卿学姐喜欢和她一样美丽的花。所以卿学姐家的后院有很多的花坛。
卿学姐有\(n\)个花坛,一开始第\(i\)个花坛里有\(A[i]\)朵花。每过一段时间,卿学姐都会在花坛里种上新的花。
作为一个聪明的学姐,卿学姐的种花方式也是与众不同 , 每一次,卿学姐会在第\(x\)个花坛种上\(y\)朵花,然后在第\(x+1\)个花坛上种上\(y-1\)朵花,再在第\(x+2\)个花坛上种上\(y-2\)朵花......以此类推,直到种到最后一个花坛,或者不需要种花为止。
喵哈哈的村民们都喜欢去卿学姐的后院赏花,沈宝宝也不例外。然而沈宝宝可不是省油的灯,怎么可能会老老实实地赏花呢。每次沈宝宝来时,都会随机询问卿学姐在第\(i\)个花坛有多少朵花。
花坛的花实在太多了,卿学姐实在是数不过来。于是现在她向你求助,希望你能帮她数出花坛里多少朵花。
Input
第一行输入两个整数,花坛个数\(N\)和操作次数\(Q\)。第二行\(N\)个整数\(A[1],A[2],A[3].....A
\)。 ( $1 \leq A[i] \leq 2^{31} $ )
接下来\(Q\)行,每行一个操作。
1 x y表示卿学姐会在\(x\)号花坛种\(y\)朵花,并按相应的规律在后面的花坛上种花。
2 x表示沈宝宝问卿学姐第\(x\)个花坛有多少朵花。
数据保证:
$1 \leq N \leq 10^4 $
$1 \leq Q \leq {2*10^6} $
$\sum x \leq 10^8 \(,\)x$代表操作 \(2\) 的询问下标
对于操作 $ 1 $ , \(1 \leq x \leq N\),\(1 \leq y \leq 10^9\)
对于操作 $ 2 $ , \(1 \leq x \leq N\)
Output
对于每个询问操作,按顺序输出答案对\(772002 + 233\)取模的值。Sample Input
6 31 2 3 2 1 2
1 2 3
2 3
2 6
Sample Output
52
Hint
题意
题解:
最简单的方法,O(N)去更新,然后O(1)去查询就好了,但是显然这样子会TLE的然后我们注意,我们发现这道保证查询操作的sigmax<=1e8
所以我们把这个变成O(1)更新,O(N)查询就好了,这个东西打个延时标记就好了。
比如1 x y
我只需要使得lazy[x]+=y,表示x这个位置需要往下更新的大小增加y
ed[x+y]++,表示某一个更新会在x+y这个位置停止。
num[x]++,表示x这个位置多了一个更新。
然后我们查询2 x的时候
我们只需要从1这个位置,一直for到x这个位置就好了,然后处理我们刚才打上去的延迟标记。
add表示现在累计了多少的值,Num表示现在我有多少个更新。
add+=lazy[i],
Num+=num[i],Num-=ed[i]。
a[i] = (a[i]+add)%mod;
add-=Num。显然走一步,就会减少Num
然后就完了~
然后有人会深入去思考,假设没有那个 sigma x<=1e8怎么办?
其实查询和更新均摊一下就好了:
有两种,
1.分块,这个方法可以把查询和更新操作都均摊到O(sqrt(n)),直接暴力更新这个值在这个块内的数据,然后再暴力更新其他大块就好了
2.线段树,直接暴力去怼线段树就好了
下面是代码:
正解大暴力
#include<bits/stdc++.h> using namespace std; const int maxn = 1e4+5; const int mod = 772002+233; long long a[maxn],lazy[maxn],num[maxn],ed[maxn]; int n,m; void updata(int x,long long y) { lazy[x]+=y; num[x]++; ed[min(1ll*n+1,x+y)]++; } long long query(int x) { long long add = 0; long long Num = 0; for(int i=1;i<=x;i++) { add+=lazy[i]; Num+=num[i]; Num-=ed[i]; lazy[i]=num[i]=ed[i]=0; a[i]=(a[i]+add)%mod; add-=Num; } lazy[x+1]+=add,num[x+1]+=Num; return a[x]; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]%=mod; for(int i=1;i<=m;i++) { int op,x; long long y; scanf("%d",&op); if(op==1) { scanf("%d%lld",&x,&y); updata(x,y); } else { scanf("%d",&x); printf("%lld\n",query(x)); } } }
迷之分块
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5+7; const int mod = 772002+233; long long a[maxn]; int l[1000],r[1000]; int block,num,belong[maxn]; long long lazy[maxn],number[maxn],ed[maxn]; int n,m; void updata(int x,long long y) { for(int i=x;i<=r[belong[x]];i++) { a[i]=(a[i]+y)%mod; y--;if(y==0)return; } for(int i=belong[x]+1;i<=num;i++) { lazy[l[i]]+=y; number[l[i]]++; if(y<(r[i]-l[i]+1)) { ed[l[i]+y]++; break; } y-=(r[i]-l[i]+1); } } long long query(int x) { long long add = 0; long long Num = 0; for(int i=l[belong[x]];i<=r[belong[x]];i++) { add+=lazy[i]; Num+=number[i]; Num-=ed[i]; lazy[i]=number[i]=ed[i]=0; a[i]=(a[i]+add)%mod; add-=Num; } return a[x]%mod; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%lld",&a[i]),a[i]%=mod;; block=(int)sqrt(n+0.5); num = n/block; if(n%block)num++; for(int i=1;i<=num;i++) l[i]=(i-1)*block+1,r[i]=i*block; r[num]=n; for(int i=1;i<=n;i++) belong[i]=(i-1)/block+1; for(int i=1;i<=m;i++) { int op,x,y; scanf("%d",&op); if(op==1) { scanf("%d%lld",&x,&y); updata(x,y); } else { scanf("%d",&x); printf("%lld\n",query(x)); } } }
线段树(1)
#include <iostream> #include <algorithm> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #define lid (id << 1) #define rid (id << 1 | 1) using namespace std; typedef long long LL; const int N = 1e4 + 10; const LL MOD = 772002 + 233; int n,q; LL a ; struct Segtree{ int l,r; LL time,cnt; }tr[N * 4]; void Segtree_Initial(int id,int l,int r) { tr[id].l = l; tr[id].r = r; tr[id].time = tr[id].cnt = 0; if(l != r) { int mid = (l + r) >> 1; Segtree_Initial(lid,l,mid); Segtree_Initial(rid,mid + 1,r); } } void Segtree_Update(int id,int l,int r,LL x) { if(l > r) return; if(tr[id].l == l && tr[id].r == r) { tr[id].time++; tr[id].cnt += x; return; } int mid = (tr[id].l + tr[id].r) >> 1 ; Segtree_Update(lid,l,min(mid , r),x); Segtree_Update(rid,max(l , mid + 1),r,x - max(mid + 1 - l , 0) ); } LL Segtree_Query(int id,int pos) { if(tr[id].l > pos || tr[id].r < pos) return 0; LL tot = tr[id].cnt - (1LL * (pos - tr[id].l) * 1LL) * tr[id].time; if(tr[id].l != tr[id].r) tot += Segtree_Query(lid,pos) + Segtree_Query(rid,pos); return tot; } void init() { scanf("%d%d",&n,&q); for(int i = 1;i <= n;i++) scanf("%lld",&a[i]); Segtree_Initial(1,1,n); } void work() { int s,pos,x,l,r; LL y,ans; for(int i = 1;i <= q;i++) { scanf("%d",&s); if(s == 1) { scanf("%d%lld",&x,&y); l = x,r = x + int(y) - 1; if(r >= n) r = n; Segtree_Update(1,l,r,y); } else { scanf("%d",&pos); ans = (Segtree_Query(1,pos) + a[pos]) % MOD; printf("%lld\n",ans); } } } int main() { init(); work(); }
线段树(2)
#include <cstdio> #define MAX_N 10004 #define lchild l, m, v << 1 #define rchild m + 1, r, v << 1 | 1 typedef long long ll; int N, Q; ll A[MAX_N]; const ll mod = 772002 + 233; void add(ll &x, ll a){ x = (x + a) % mod; } struct SegmentTree{ struct node{ ll coverTime; ll headNum; }tree[MAX_N * 4]; SegmentTree(); void build(int, int, int); void pushDown(int, int, int); void update(int, int, ll, int, int, int); ll query(int, int, int, int); }seg; SegmentTree::SegmentTree(){ for(int i = 0; i < MAX_N * 4; i++) tree[i].coverTime = tree[i].headNum = 0; } void SegmentTree::build(int l = 1,int r = N, int v = 1){ if(l == r){ tree[v].headNum = A[l]; return; } int m = (l + r) >> 1; build(lchild); build(rchild); } void SegmentTree::pushDown(int l, int r, int v){ int m = (l + r) >> 1; add(tree[v << 1].coverTime, tree[v].coverTime); add(tree[v << 1 | 1].coverTime, tree[v].coverTime); add(tree[v << 1].headNum, tree[v].headNum); add(tree[v << 1 | 1].headNum, (tree[v].headNum - (m - l + 1) * tree[v].coverTime % mod) % mod); tree[v].coverTime = tree[v].headNum = 0; } void SegmentTree::update(int L, int R, ll x, int l = 1, int r = N, int v = 1){ if(L <= l && r <= R){ add(tree[v].headNum, x - (l - L)); add(tree[v].coverTime, 1); return; } if(tree[v].coverTime) pushDown(l, r, v); int m = (l + r) >> 1; if(L <= m) SegmentTree::update(L, R, x, lchild); if(R > m) SegmentTree::update(L, R, x, rchild); } ll SegmentTree::query(int a, int l = 1, int r = N, int v = 1){ if(l == r) return (tree[v].headNum %mod + mod) % mod; if(tree[v].coverTime) pushDown(l, r, v); int m = (l + r) >> 1; if(a <= m) return SegmentTree::query(a, lchild); else return SegmentTree::query(a, rchild); } int main(){ scanf("%d%d", &N, &Q); for(int i = 1; i <= N; i++) scanf("%lld", &A[i]); seg.build(); while(Q--){ int op, x, y; scanf("%d%d", &op, &x); if(op == 1){ scanf("%d", &y); int z = x + y - 1 > N ? N : x + y - 1; seg.update(x, z, y); } else printf("%lld\n", seg.query(x)); } return 0; }
相关文章推荐
- Flex 布局教程:语法篇
- hdu 5572 An Easy Physics Problem
- CSP考试 2015年9月第2题 日期计算 C语言实现
- 微博API iOS9的适配问题
- spring+mybatis使用事务管理不生效原因分析
- 读书笔记----javascript类和模块
- 数据结构上机2.1
- web表格代码(5)
- 详细解析 RxAndroid 的使用方式
- 结对编程项目(二)
- [Awt]——太空猛禽
- 利用excel办公软件快速拼凑sql语句
- 正则表达式替换foreach_if_elseif_else
- 【HPU】[1730]字符串
- 《leetCode》:Factorial Trailing Zeroes
- Oracle Grid 11.2.0.4 $GI_HOME/crs/config/config.sh 出现INS-06001
- 世界是数字的观后感
- fragment、ListFragment使用ListView及自定义Listview等初始化操作
- OC篇学习-字典
- 利用excel办公软件快速拼凑sql语句