【nowcoder】Tree Recovery(线段树-区间更新 / 前缀和与差分)
2018-02-26 14:13
363 查看
链接:https://www.nowcoder.com/acm/contest/77/H
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
输入描述:
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.
输出描述:
You need to answer all Q commands in order. One answer in a line.
示例1
输入
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
输出
4
55
9
15
分析:题目数据比较弱,可以直接暴力求解
另外可用一维前缀和与差分 复杂度 O(n)
当数据较大,可用线段树的区间更新求和 模板
【前缀和与差分】代码:
/**
给定序列a,对[l,r] 的所有元素都加上k,求[L,R]的ai和
用前缀和求解 O(n)
///p[i]=a[i]-a[i-1]
对【l,r】内元素加k 转化为 p[l]+=k,p[r+1]-=k;
然后对修改后的数组a求和
一旦n过大,还是不适用
**/
【线段树 区间更新模板】
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
输入描述:
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.
输出描述:
You need to answer all Q commands in order. One answer in a line.
示例1
输入
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
输出
4
55
9
15
分析:题目数据比较弱,可以直接暴力求解
另外可用一维前缀和与差分 复杂度 O(n)
当数据较大,可用线段树的区间更新求和 模板
【前缀和与差分】代码:
/**
给定序列a,对[l,r] 的所有元素都加上k,求[L,R]的ai和
用前缀和求解 O(n)
///p[i]=a[i]-a[i-1]
对【l,r】内元素加k 转化为 p[l]+=k,p[r+1]-=k;
然后对修改后的数组a求和
一旦n过大,还是不适用
**/
#include <bits/stdc++.h> using namespace std; #define mem(a,n) memset(a,n,sizeof(a)) #define memc(a,b) memcpy(a,b,sizeof(b)) #define rep(i,a,n) for(int i=a;i<n;i++) ///[a,n) #define dec(i,n,a) for(int i=n;i>=a;i--)///[n,a] #define pb push_back #define fi first #define se second #define IO ios::sync_with_stdio(false) #define fre freopen("in.txt","r",stdin) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 typedef long long ll; typedef unsigned long long ull; const double PI=acos(-1.0); const double E=2.718281828459045; const double eps=1e-3; const int INF=0x3f3f3f3f; const int MOD=258280327; const int N=1e5+5; const ll maxn=1e6+5; const int dir[4][2]= {-1,0,1,0,0,-1,0,1}; int a ,p ; int n,q; void add(int l,int r,int k) { p[l]+=k,p[r+1]-=k; } void get_a() { rep(i,1,n+1) a[i]=a[i-1]+p[i]; } int main() { while(~scanf("%d%d",&n,&q)) { mem(a,0); mem(p,0); rep(i,1,n+1) { scanf("%d",&a[i]); p[i]=a[i]-a[i-1]; } while(q--) { char op; scanf(" %c",&op); if(op=='C') { int l,r,k; scanf("%d%d%d",&l,&r,&k); add(l,r,k); get_a(); } else { int l,r; scanf("%d%d",&l,&r); ll sum=0; rep(i,l,r+1) sum+=a[i]; printf("%lld\n",sum); } } } return 0; }
【线段树 区间更新模板】
#include <bits/stdc++.h> using namespace std; #define mem(a,n) memset(a,n,sizeof(a)) #define memc(a,b) memcpy(a,b,sizeof(b)) #define rep(i,a,n) for(int i=a;i<n;i++) ///[a,n) #define dec(i,n,a) for(int i=n;i>=a;i--)///[n,a] #define pb push_back #define fi first #define se second #define IO ios::sync_with_stdio(false) #define fre freopen("in.txt","r",stdin) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 typedef long long ll; typedef unsigned long long ull; const double PI=acos(-1.0); const double E=2.718281828459045; const double eps=1e-3; const int INF=0x3f3f3f3f; const int MOD=258280327; const int N=1e5+5; const ll maxn=1e6+5; const int dir[4][2]= {-1,0,1,0,0,-1,0,1}; ll sum[N<<2],a ,MAX[N<<2],ad[N<<2]; void pushup(ll rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; // MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]); } void pushdown(int rt,int m) { if(ad[rt]) { ad[rt<<1]+=ad[rt]; ad[rt<<1|1]+=ad[rt]; sum[rt<<1]+=ad[rt]*(m-(m>>1)); sum[rt<<1|1]+=ad[rt]*(m>>1); ad[rt]=0; ///标记清除!!! } } void build(ll l,ll r,ll rt) { ad[rt]=0; if(l==r) { scanf("%lld",&sum[rt]); return ; } ll m=(l+r)>>1; build(lson); build(rson); pushup(rt); } void update(ll L,ll R,ll c,ll l,ll r,ll rt) { if(L<=l&&R>=r) { ad[rt]+=c; sum[rt]+=c*(r-l+1); return ; } pushdown(rt,r-l+1); ll m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); pushup(rt); } ll query(ll L,ll R,ll l,ll r,ll rt) { if(L<=l&&R>=r) { return sum[rt]; } pushdown(rt,r-l+1); ll m=(l+r)>>1; ll ret=0; if(L<=m) ret+=query(L,R,lson); if(R>m) ret+=query(L,R,rson); return ret; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { build(1,n,1); for(int i=0; i<m; i++) { char op; ll a,b,c; scanf(" %c",&op); if(op=='Q') { scanf("%lld%lld",&a,&b); printf("%lld\n",query(a,b,1,n,1)); } else { scanf("%lld%lld%lld",&a,&b,&c); update(a,b,c,1,n,1); } } } return 0; }
相关文章推荐
- poj 1201 interval 差分约束/贪心+线段树区间更新
- 线段树、前缀数组:HDU1591-Color the ball(区间更新、简单题)
- 哈理工OJ 2256 南西群岛海域·冲之岛近海(线段树区间更新+前缀和优化)
- 2016 Multi-University Training Contest 10 [HDU 5861] Road (线段树区间更新+差分数组)
- 喵哈哈村的种花魔法(线段树(区间更新,单点查询),前缀和(单点更新,区间查询))
- ccnu-线段树-简单的区间更新(三题)
- HDU 3966 Aragorn's Story(树链剖分+线段树区间更新+手动扩大内存)
- POJ 3225 Help with Intervals【线段树 区间更新 异或运算】
- ZOJ 5638——Prime Query——————【线段树区间更新,区间查询,单点更新】
- hdu1698 线段树区间更新
- 线段树区间更新760E
- poj 2528(线段树区间更新)
- ZOJ 1610 Count the Colors(线段树——区间更新)(成段染色)
- 线段树·HDU1166 敌兵布阵·单点更新区间求和
- poj 3468 线段树区间更新lazy
- hdu1166敌兵布阵(线段树---单点更新,区间求值)
- HDU 1166 敌兵布阵(线段树:点更新,区间求和)
- UVA 12436 Rip Van Winkle's Code(线段树区间更新)
- LCIS线段树(区间更新)
- 线段树--区间更新