题目较多就不贴了^_^
都是线段树入门模板题
1080 线段树练习1
单点更新+区间查询
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
int w[100010];
struct node{
int left;
int right;
int sum;
int addv;
}a[400040];
void build(int l,int r,int p){
a[p].left=l;a[p].right=r;
if(l==r) { a[p].sum=w[l];return ;}
if(l<r){
build(l,(l+r)/2,2*p);
build((l+r)/2+1,r,2*p+1);
a[p].sum=a[2*p].sum+a[2*p+1].sum;
}
}
void pushdown(int p){
if(a[p].addv!=0){
a[2*p].addv+=a[p].addv;
a[2*p].sum+=a[p].addv*(a[2*p].right-a[2*p].left+1);
a[2*p+1].addv=a[p].addv;
a[2*p+1].sum+=a[p].addv*(a[2*p+1].right-a[2*p+1].left+1);
a[p].addv=0;
}
}
void update(int x,int p,int d){
if(a[p].left==x&&a[p].right==x){
a[p].sum+=d;a[p].addv+=d;return ;
}
pushdown(p);
int mid=(a[p].left+a[p].right)/2;
if(x<=mid) update(x,2*p,d);
else if(x>mid) update(x,2*p+1,d);
a[p].sum=a[2*p].sum+a[2*p+1].sum;
}
int query(int l,int r,int p){
if(a[p].left==l&&a[p].right==r)
return a[p].sum;
pushdown(p);
int mid=(a[p].left+a[p].right)/2;
if(r<=mid) return query(l,r,2*p);
else if(l>mid) return query(l,r,2*p+1);
else return query(l,mid,2*p)+query(mid+1,r,2*p+1);
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
build(1,n,1);
int m;
scanf("%d",&m);
while(m--){
int k,x,y;
scanf("%d%d%d",&k,&x,&y);
if(k==1)
update(x,1,y);
else
printf("%d\n",query(x,y,1));
}
return 0;
}
线段树练习2
区间更新+单点查询
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
int w[100010];
struct node{
int left;
int right;
int sum;
int addv;
}a[400040];
void build(int l,int r,int p){
a[p].left=l;a[p].right=r;
if(l==r) { a[p].sum=w[l];return ;}
if(l<r){
build(l,(l+r)/2,2*p);
build((l+r)/2+1,r,2*p+1);
a[p].sum=a[2*p].sum+a[2*p+1].sum;
}
}
void pushdown(int p){
if(a[p].addv!=0){
a[2*p].addv+=a[p].addv;
a[2*p].sum+=a[p].addv*(a[2*p].right-a[2*p].left+1);
a[2*p+1].addv+=a[p].addv;
a[2*p+1].sum+=a[p].addv*(a[2*p+1].right-a[2*p+1].left+1);
a[p].addv=0;
}
}
void update(int l,int r,int p,int d){
if(a[p].left==l&&a[p].right==r){
a[p].sum+=d;a[p].addv+=d;return ;
}
pushdown(p);
int mid=(a[p].left+a[p].right)/2;
if(r<=mid) update(l,r,2*p,d);
else if(l>mid) update(l,r,2*p+1,d);
else{
update(l,mid,2*p,d);update(mid+1,r,2*p+1,d);
}
a[p].sum=a[2*p].sum+a[2*p+1].sum;
}
int query(int x,int p){
if(a[p].left==x&&a[p].right==x)
return a[p].sum;
pushdown(p);
int mid=(a[p].left+a[p].right)/2;
if(x<=mid) return query(x,2*p);
else if(x>mid) return query(x,2*p+1);
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
build(1,n,1);
int m;
scanf("%d",&m);
while(m--){
int k,x,y,d;
scanf("%d",&k);
if(k==1){
scanf("%d%d%d",&x,&y,&d);
update(x,y,1,d);
}
else {
scanf("%d",&x);
printf("%d\n",query(x,1));
}
}
return 0;
}
线段树练习3
区间更新+区间查询
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
int w[200010];
struct node{
int left;
int right;
ll sum;
ll addv;
}a[800080];
void build(int l,int r,int p){
a[p].left=l;a[p].right=r;
if(l==r) { a[p].sum=w[l];return ;}
if(l<r){
build(l,(l+r)/2,2*p);
build((l+r)/2+1,r,2*p+1);
a[p].sum=a[2*p].sum+a[2*p+1].sum;
}
}
void pushdown(int p){
if(a[p].addv!=0){
a[2*p].addv+=a[p].addv;
a[2*p].sum+=a[p].addv*(a[2*p].right-a[2*p].left+1);
a[2*p+1].addv+=a[p].addv;
a[2*p+1].sum+=a[p].addv*(a[2*p+1].right-a[2*p+1].left+1);
a[p].addv=0;
}
}
void update(int l,int r,int p,int d){
if(a[p].left==l&&a[p].right==r){
a[p].sum+=(r-l+1)*d;a[p].addv+=d;return ;
}
pushdown(p);
int mid=(a[p].left+a[p].right)/2;
if(r<=mid) update(l,r,2*p,d);
else if(l>mid) update(l,r,2*p+1,d);
else{
update(l,mid,2*p,d);update(mid+1,r,2*p+1,d);
}
a[p].sum=a[2*p].sum+a[2*p+1].sum;
}
ll query(int l,int r,int p){
if(a[p].left==l&&a[p].right==r)
return a[p].sum;
pushdown(p);
int mid=(a[p].left+a[p].right)/2;
if(r<=mid) return query(l,r,2*p);
else if(l>mid) return query(l,r,2*p+1);
else return query(l,mid,2*p)+query(mid+1,r,2*p+1);
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
build(1,n,1);
int m;
scanf("%d",&m);
while(m--){
int k,x,y;
ll d;
scanf("%d",&k);
if(k==1){
scanf("%d%d%lld",&x,&y,&d);
update(x,y,1,d);
}
else {
scanf("%d%d",&x,&y);
printf("%lld\n",query(x,y,1));
}
}
return 0;
}
线段树练习4
嗯 此题有点变化 难度高于上面三题 区间更新+求%7==0的
方法就是记录下mod7的余数 然后每次做加法相当于向右平移数组元素
addv这个加值记录平移量 然后就没了。。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100010
using namespace std;
int w[N];int temp[N];
struct node{
int left;
int right;
int sum[7];
int addv;
}a[4*N];
void build(int l,int r,int p){
a[p].left=l;a[p].right=r;
if(l==r){ a[p].sum[w[l]%7]++; return;}
if(l<r) {
build(l,(l+r)/2,2*p);
build((l+r)/2+1,r,2*p+1);
for(int i=0;i<=6;i++)
a[p].sum[i]=a[2*p].sum[i]+a[2*p+1].sum[i];
}
}
void deal(int p,int k){
//平移函数
if(k!=0){
for(int i=0;i<=6;i++)
temp[(i+k)%7]=a[p].sum[i];
for(int i=0;i<=6;i++)
a[p].sum[i]=temp[i];
}
}
void pushdown(int p){
//往下传值函数
if(a[p].addv!=0){
a[2*p].addv+=a[p].addv;
deal(2*p,a[p].addv);
a[2*p+1].addv+=a[p].addv;
deal(2*p+1,a[p].addv);
a[p].addv=0;
}
}
void update(int l,int r,int p,int x){
if(a[p].left==l&&a[p].right==r)
{deal(p,x); a[p].addv+=x; return;}
pushdown(p);
int mid=(a[p].left+a[p].right)/2;
if(r<=mid) update(l,r,2*p,x);
else if(l>mid) update(l,r,2*p+1,x);
else {
update(l,mid,2*p,x);
update(mid+1,r,2*p+1,x);
}
for(int i=0;i<=6;i++)
a[p].sum[i]=a[2*p].sum[i]+a[2*p+1].sum[i];
}
int query(int l,int r,int p){
if(a[p].left==l&&a[p].right==r)
return a[p].sum[0];
pushdown(p);
int mid=(a[p].left+a[p].right)/2;
if(r<=mid) return query(l,r,2*p);
else if(l>mid) return query(l,r,2*p+1);
else return query(l,mid,2*p)+query(mid+1,r,2*p+1);
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
w[i]=x%7;
}
build(1,n,1);
int m;
scanf("%d",&m);
char ss[10];
while(m--){
getchar();
scanf("%s",&ss);
int x,y,k;
if(ss[0]=='c') {
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y,1));
}
else {
scanf("%d%d%d",&x,&y,&k);
k%=7;
//时刻记得mod7
update(x,y,1,k);
}
}
return 0;
}