題目描述:
qn姐姐最好了~
qn姐姐給你了乙個長度為n的序列還有m次操作讓你玩,
1 l r 詢問區間[l,r]內的元素和
2 l r 詢問區間[l,r]內的元素的平方和
3 l r x 將區間[l,r]內的每乙個元素都乘上x
4 l r x 將區間[l,r]內的每乙個元素都加上x
第一行兩個數n,m
接下來一行n個數表示初始序列
就下來m行每行第乙個數為操作方法opt,
若opt=1或者opt=2,則之後跟著兩個數為l,r
若opt=3或者opt=4,則之後跟著三個數為l,r,x
操作意思為題目描述裡說的
對於每乙個操作1,2,輸出一行表示答案
示例1
5 6
1 2 3 4 5
1 1 5
2 1 5
3 1 2 1
4 1 3 2
1 1 4
2 2 3
15
5516
41
對於100%的資料 n=10000,m=200000 (注意是等於號)
保證所有詢問的答案在long long 範圍內
出題人題解:
顯然,線段樹
記錄4個東西,區間和tree[root][0],區間平方和 tree[root][1],乘法懶標記 add2[root],加法懶標記add1[root] 。
查詢的話就是常規查詢,打標記就是線段樹2板子一樣,
初值:add1[root]=0,add2[root]=1;
加法:add1[root]+=dx
乘法:add2[root]*=dx;
然後考慮更新答案
當前區間[l,r] ,當前節點root,這裡面每個元素都變成了( a[i]為更新後, x[i]為更新前)
所以
利用線段樹處理區間和與區間平方和
利用性質(a+b)^2
區間和的話比較容易了,
然後lazy有點麻煩
然後就標準線段樹板子
線段樹模板:
#include#include#includeusing namespace std;
#define maxn 10005
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
long long n,m,tree[maxn<<2][2],add1[maxn<<2],add2[maxn<<2];
void pushup(long long root)
void pushdown1(long long l,long long r,long long root)
}void pushdown2(long long l,long long r,long long root)
}void build(long long l,long long r,long long root)
long long mid=(l+r)>>1;
build(lson);
build(rson);
pushup(root);
}void update1(long long l,long long r,long long c,long long l,long long r,long long root)
long long mid = (l+r)/2;
pushdown2(mid-l+1,r-mid,root); pushdown1(mid-l+1,r-mid,root);
if(l<=mid)
update1(l,r,c,lson);
if(r>mid)
update1(l,r,c,rson);
pushup(root);
}void update2(long long l,long long r,long long c,long long l,long long r,long long root)
long long mid = (l+r)/2;
pushdown2(mid-l+1,r-mid,root); pushdown1(mid-l+1,r-mid,root);
if(l<=mid)
update2(l,r,c,lson);
if(r>mid)
update2(l,r,c,rson);
pushup(root);
}long long query(long long l,long long r,long long c,long long l,long long r,long long root)
long long ans=0,mid=(l+r)>>1;
pushdown2(mid-l+1,r-mid,root); pushdown1(mid-l+1,r-mid,root);
if(l<=mid)
ans+=query(l,r,c,lson);
if(r>mid)
ans+=query(l,r,c,rson);
return ans;
}int main()
else if(op==3||op==4)
}return 0;
}
**:題解
第二種。。。
#include#include#include#include#include#define n 100005
using namespace std;
typedef long long ll;
struct node
tree[n];
ll a[10005];
int n, m;
void build(int g, int l, int r)
int mid = (l + r) >> 1;
build(g * 2, l, mid);
build(g * 2 + 1, mid + 1, r);
tree[g].mulzy = 1;
tree[g].sum = tree[g * 2].sum + tree[g * 2 + 1].sum;
tree[g].mul = tree[g * 2].mul + tree[g * 2 + 1].mul;
}void updata(int p, int l, int r)
void insert(int p, int l, int r, int a, int b, ll x, int opt)
updata(p,l,r);
if (mid >= b)
insert(p * 2, l, mid, a, b, x, opt);
else if (a > mid)
insert(p * 2 + 1, mid + 1, r, a, b, x, opt);
else
tree[p].sum = tree[p * 2].sum + tree[p * 2 + 1].sum;
tree[p].mul = tree[p * 2].mul + tree[p * 2 + 1].mul;
}ll get_sum(int p, int l, int r, int a, int b, int opt)
updata(p, l, r);
if (mid >= b)
return get_sum(p * 2, l, mid, a, b, opt);
else if (a > mid)
return get_sum(p * 2 + 1, mid + 1, r, a, b, opt);
else return get_sum(p * 2, l, mid, a, mid, opt) + get_sum(p * 2 + 1, mid + 1, r, mid + 1, b, opt);
}int main()
if (opt == 3 || opt == 4)
}return 0;
}
《牛客練習賽28 B》
這題主要就是多了乙個平方和的操作。我們維護平方和的值的時候。需要注意在下放的時候,要先把乘法之後的sum1算出來,這對算sum1最終的值沒有影響。但是對sum2的值有影響。因為我們在計算中就在更新adtag的值,所以這個adtag它的sum1應該最終化。includeusing namespace ...
資料結構 線段樹 牛客練習賽28B
op 1 sum op 2 sum2 平方和 op 3 mul op 4 add 2個lazy標記 include include using namespace std define lc rt 1 define rc rt 1 1 define mid l r 2 typedef long lo...
牛客練習賽28 B 複習線段樹 )
description qn姐姐給你了乙個長度為n的序列還有m次操作讓你玩,1 l r 詢問區間 l,r 內的元素和 2 l r 詢問區間 l,r 內的元素的平方和 3 l r x 將區間 l,r 內的每乙個元素都乘上x 4 l r x 將區間 l,r 內的每乙個元素都加上x input n,mop...