1.最大数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 200005;
int m,p;
struct Tree{
int l,r;
int v; //最大值属性.
}tr[N * 4];
void pushup(int u){
tr[u].v = max(tr[u<<1].v,tr[u<<1|1].v);
}
// 由于不更新属性值,所以不需要向上向下传递影响(push)
void build(int u,int l,int r){
tr[u] = {
l,r}; // ?
if(l==r){
// tr[u] = {l,r};
return;
}
int mid = (l + r) >> 1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
}
int query(int u,int l,int r){
//区间查询:从根节点开始查询区间的属性
if(l<=tr[u].l && tr[u].r<=r) return tr[u].v;
int v = 0;
int mid = (tr[u].l + tr[u].r) >> 1;
if(l<=mid) v = query(u<<1,l,r);
if(r>mid) v = max(v,query(u<<1|1,l,r));
// pushup(u);
return v;
}
void motify(int u,int x,int val){
// 单点修改:从根节点开始查询到x,修改其属性为val;后进行pushup操作(向上传递影响)
if(tr[u].l==x && tr[u].r==x){
tr[u].v = val;
return;
}
int mid = (tr[u].l + tr[u].r) >> 1;
if(x<=mid){
motify(u<<1,x,val);
}else{
motify(u<<1|1,x,val);
}
pushup(u);
}
int main()
{
scanf("%d%d",&m,&p);
build(1,1,m);
char s[2];
int x;
int n = 0;
int last = 0;
while(m--){
scanf("%s%d",s,&x);
if(*s=='Q'){
last = query(1,n-x+1,n);
printf("%d\n",last);
}else{
motify(1,n+1,((ll)last+x)%p);
n++;
}
}
return 0;
}
- 单点修改,区间查询
线段树存储差分数组.
某一区间上的最大子段和分为三种情况:(取max)
1.左子区间上的最大子段和.
2.右子区间上的最大子段和.
3.横跨两个区间的最大子段和(左子区间上的右连续最大子段和+右子区间上的左连续最大子段和).
计算某一区间上的最大左连续子段和分为两种情况:(取max)
1.左子区间的最大左连续子段和.
2.左子段和+右子区间的最大左连续子段.
需要维护线段树属性:
最大子段和、左连续最大子段和、右连续最大子段和、区间和.
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 500010;
int n,m;
struct Node{
int l,r;
int tmax,lmax,rmax,sum;
}tr[N*4];
int w[N];
void pushup(Node &u,Node &l,Node &r){
u.sum = l.sum + r.sum;
u.lmax = max(l.lmax,l.sum+r.lmax);
u.rmax = max(r.rmax,r.sum+l.rmax);
u.tmax = max(max(l.tmax,r.tmax),l.rmax+r.lmax);
}
void pushup(int u){
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(int u,int l,int r){
if(l==r) tr[u] = {
l,r,w[r],w[r],w[r],w[r]};
else{
tr[u] = {
l,r};
int mid = (l+r) >> 1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
}
Node query(int u,int l,int r){
if(tr[u].l>=l && tr[u].r<=r) return tr[u];
else{
int mid = (tr[u].l + tr[u].r) >> 1;
if(r<=mid) return query(u<<1,l,r);
else if(l>mid) return query(u<<1|1,l,r);
else{
auto left = query(u<<1,l,r);
auto right = query(u<<1|1,l,r);
Node res;
pushup(res,left,right);
return res;
}
}
}
void modify(int u,int x,int val){
if(tr[u].l==x && tr[u].r==x) tr[u] = {
x,x,val,val,val,val};
else{
int mid = (tr[u].l + tr[u].r) >> 1;
if(x<=mid) modify(u<<1,x,val);
else modify(u<<1|1,x,val);
pushup(u);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
build(1,1,n);
int k,x,y;
while(m--){
scanf("%d%d%d",&k,&x,&y);
if(k == 1){
if(x>y) swap(x,y);
auto ans = query(1,x,y);
printf("%d\n",ans.tmax);
}else{
modify(1,x,y);
}
}
return 0;
}
3.简单的整数问题(区间查询,区间修改,使用懒标记)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 100010;
int n,m;
int w[N];
struct Tree{
int l,r;
ll sum,add;
}tr[N*4];
void pushup(int u){
tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;
}
void pushdown(int u){
Tree &root = tr[u];
Tree &l = tr[u<<1];
Tree &r = tr[u<<1|1];
if(root.add){
l.add += root.add, l.sum += (ll)(l.r - l.l + 1)*root.add;
r.add += root.add, r.sum += (ll)(r.r - r.l + 1)*root.add;
root.add = 0;
}
}
void build(int u,int l,int r){
tr[u] = {
l,r};
if(l==r){
tr[u] = {
l,l,w[l],0};
return;
}
int mid = (l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
ll query(int u,int l,int r){
if(tr[u].l>=l && tr[u].r<=r) return tr[u].sum;
pushdown(u);
ll sum = 0;
int mid = (tr[u].l + tr[u].r) >> 1;
if(l<=mid) sum += query(u<<1,l,r);
if(r>mid) sum += query(u<<1|1,l,r);
return sum;
}
void modify(int u,int l,int r,int d){
if(tr[u].l>=l && tr[u].r<=r){
tr[u].sum += (tr[u].r - tr[u].l + 1)*d;
tr[u].add += d;
return;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(l<=mid) modify(u<<1,l,r,d);
if(r>mid) modify(u<<1|1,l,r,d);
pushup(u);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
build(1,1,n);
while(m--){
char str[3];
int l,r,d;
scanf("%s%d%d",str,&l,&r);
if(*str=='Q'){
printf("%lld\n",query(1,l,r));
}else{
scanf("%d",&d);
modify(1,l,r,d);
}
}
return 0;
}
4.维护序列
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 100010;
int n,p,m;
int w[N];
struct Tree{
int l,r;
int sum,add,mul;
}tr[N*4];
void eval(Tree &t,int add,int mul){
t.sum = ((ll)t.sum * mul + (ll)(t.r - t.l + 1) * add) % p;
t.mul = ((ll)t.mul * mul) % p;
t.add = ((ll)t.add * mul + add) % p;
}
void pushup(int u){
tr[u].sum = (tr[u<<1].sum + tr[u<<1|1].sum) % p;
}
void pushdown(int u){
eval(tr[u<<1],tr[u].add,tr[u].mul);
eval(tr[u<<1|1],tr[u].add,tr[u].mul);
tr[u].add = 0,tr[u].mul = 1;
}
void build(int u,int l,int r){
if(l==r){
tr[u] = {
l,l,w[l],0,1};
}else{
tr[u] = {
l,r,0,0,1};
int mid = (l + r) >> 1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
int query(int u,int l,int r){
if(tr[u].l>=l && tr[u].r<=r) return tr[u].sum;
pushdown(u);
int sum = 0;
int mid = (tr[u].l + tr[u].r) >> 1;
if(l<=mid) sum = query(u<<1,l,r);
if(r>mid) sum = (sum + query(u<<1|1,l,r))%p;
return sum;
}
void modify(int u,int l,int r,int add,int mul){
if(tr[u].l>=l && tr[u].r<=r) eval(tr[u],add,mul);
else{
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(l<=mid) modify(u<<1,l,r,add,mul);
if(r>mid) modify(u<<1|1,l,r,add,mul);
pushup(u);
}
}
int main()
{
scanf("%d%d",&n,&p);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
build(1,1,n);
scanf("%d",&m);
int op,l,r;
int v;
while(m--){
scanf("%d%d%d",&op,&l,&r);
if(op==1){
scanf("%d",&v);
modify(1,l,r,0,v);
}else if(op==2){
scanf("%d",&v);
modify(1,l,r,v,1);
}else{
printf("%d\n",query(1,l,r));
}
}
return 0;
}
最后放一道debug了两个小时都不知道问题在哪的代码 nanshou ):
题目链接:线段树
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 100010;
int n,m,p;
int w[N];
int inv2;
struct Tree{
int l,r;
int sum,qsum; //维护区间和与区间平方和.
int add,mul;
}tr[N*4];
int cal(int s1,int s2){
int ans = (((ll)s1*s1%p - (ll)s2 + p)%p*(ll)inv2%p) % p;
return ans;
}
//完全正确.
void eval(Tree &t,int add,int mul){
int m = (t.l+t.r)/2;
// t.qsum = ((ll)t.qsum * mul * mul%p + (ll)(t.r - t.l + 1)*add*add%p + (ll)2*add*t.sum*mul%p + p)%p; //可能会出错.
t.qsum = ((ll)t.qsum * mul %p * mul % p + (ll)(t.r - t.l + 1ll)*add%p*add%p + (ll)2ll*add%p*t.sum%p*mul%p + p)%p;
// t.qsum = ((ll)t.qsum * mul %p * mul % p + (ll)(m - t.l + 1ll)*add%p*add%p + (ll)2ll*add%p*t.sum%p*mul%p + p)%p;
t.sum = ((ll)t.sum * mul + (ll)(t.r - t.l + 1ll) * add) % p;
t.mul = ((ll)t.mul * mul) % p;
t.add = ((ll)t.add * mul + (ll)add) % p;
}
// 正确.
void pushup(int u){
tr[u].sum = ((ll)tr[u<<1].sum + (ll)tr[u<<1|1].sum + p)%p;
tr[u].qsum = ((ll)tr[u<<1].qsum + (ll)tr[u<<1|1].qsum + p)%p;
}
//正确
void pushdown(int u){
eval(tr[u<<1],tr[u].add,tr[u].mul);
eval(tr[u<<1|1],tr[u].add,tr[u].mul);
tr[u].add = 0,tr[u].mul = 1;
}
void build(int u,int l,int r){
if(l==r){
tr[u] = {
l,l,w[l],w[l]*w[l],0,1};
return;
}
tr[u] = {
l,r,0,0,0,1};
int mid = (l + r) >> 1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,int add,int mul){
if(tr[u].l>=l && tr[u].r<=r){
eval(tr[u],add,mul);
return;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(l<=mid) modify(u<<1,l,r,add,mul);
if(r>mid) modify(u<<1|1,l,r,add,mul);
pushup(u);
}
int query(int u,int l,int r){
if(tr[u].l>=l && tr[u].r<=r) return cal(tr[u].sum,tr[u].qsum);
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
int sum = 0;
if(l<=mid) sum = query(u<<1,l,r);
if(r>mid) sum = ((ll)sum + (ll)query(u<<1|1,l,r) + p)%p;
return sum;
}
int quick_pow(int a,int b,int mod){
int ans = 1;
while(b){
if(b&1) ans = (ans * (ll)a) % mod;
a = ((ll)a * a) % mod;
b >>= 1;
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,m,p;
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
inv2 = quick_pow(2ll,p-2,p); //求逆元.
build(1,1,n);
while(m--){
int t,l,r,v;
scanf("%d%d%d",&t,&l,&r);
if(t==1){
scanf("%d",&v);
modify(1,l,r,v,1);
}else if(t==2){
scanf("%d",&v);
modify(1,l,r,0,v);
}else{
printf("%d\n",query(1,l,r));
}
}
}
return 0;
}
线段树好鸡儿难写,落泪了…