普通的线段树
只是求子结点的最大值
更新节点,区间最值.
基础模板题
线段树区间修改,点修改
区间加减乘除,平方和,根号
HDU1754 I Hate It
传送门
线段树+点修改+区间查询
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const int maxn=2e5+5;
int A[maxn];
int tree[maxn<<2];
int n,m;
int L,R,C;
void pushup(int rt){
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);//因为不是求和,所以直接获取左右结点中大的数
}
void build(int l,int r,int rt){
if(l==r){
tree[rt]=A[l];
return;
}
int m=(l+r)>>1;//线段树的平分方式
build(l,m,rt<<1);//左边,左子结点
build(m+1,r,rt<<1|1);//右边,右子结点
pushup(rt);
}
void update(int l,int r,int rt){
if(l==r){
tree[rt]=C;
return;
}
int m=(l+r)>>1;
if(L<=m)update(l,m,rt<<1);//更新在左子树
else update(m+1,r,rt<<1|1);//更新在右子树
pushup(rt);//子结点已经更新,该结点也需要更新
}
int query(int l,int r,int rt){
if(l>=L&&r<=R){
return tree[rt];
}
int m=(l+r)>>1;
int ans=0;//根据题意更新ans最小值
if(L<=m)ans=max(ans,query(l,m,rt<<1));
if(m<R)ans=max(ans,query(m+1,r,rt<<1|1));
return ans;
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++){
scanf("%d",&A[i]);
}
build(1,n,1);
for(int i=0; i<m; i++){
char str[15];
scanf("%s",str);
if(str[0]=='Q'){
scanf("%d%d",&L,&R);
cout<<query(1,n,1)<<endl;
}
else if(str[0]=='U'){
scanf("%d%d",&L,&C);
update(1,n,1);
}
}
}
return 0;
}
优化版
好像快速输入没快多少,还慢了????什么玩意?
#include<iostream>
#include<cstdio>
#include<algorithm>
#define il inline
#define ll int//套了模板,因为原来是long long,懒得改,所以就改define了
#define debug printf("%d %s\n",__LINE__,__FUNCTION__)
#define lson l,m,rt<<1//左儿子
#define rson m+1,r,rt<<1|1//右儿子
using namespace std;
const int N=200005;
ll n,m,sum[N<<2];
ll R,L,C;
il ll read(){//快速读入数字
char ch=getchar();ll x=0,f=1;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
il void pushup(int rt){
sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
}
il void build(int l,int r,int rt){
if(l==r){
sum[rt]=read();
return;
}
int m=(l+r)>>1;
build(lson),build(rson);
pushup(rt);
}
il void update(int l,int r,int rt){
if(l==r){sum[rt]=C;return;}
ll m=(l+r)>>1;
if(L<=m)update(lson);//更新在左子树
else update(rson);//更新在右子树
pushup(rt);//子结点已经更新,该结点也需要更新
}
il ll query(int l,int r,int rt){
if(L<=l&&R>=r)return sum[rt];
int m=(l+r)>>1;
ll ret=0;
if(L<=m)ret=max(ret,query(lson));
if(m<R)ret=max(ret,query(rson));
return ret;
}
int main(){
while(~scanf("%d%d",&n,&m)){
build(1,n,1);
while(m--){
char u[3];
scanf("%s",u);
if(u[0]=='U'){
L=read(),C=read();
update(1,n,1);
}
else {
L=read(),R=read();
printf("%d\n",query(1,n,1));
}
}
}
return 0;
}
HDU1166 敌兵布阵
传送门
普通线段树,同时实现加,减,最大值操作
线段树+点修改+区间查询
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const int maxn=2e5+5;
int A[maxn];
int tree[maxn<<2];
int n,m;
int L,R,C;
void pushup(int rt){
tree[rt]=tree[rt<<1]+tree[rt<<1|1];//因为不是求和,所以直接获取左右结点中大的数
}
void build(int l,int r,int rt){
if(l==r){
tree[rt]=A[l];
return;
}
int m=(l+r)>>1;//线段树的平分方式
build(l,m,rt<<1);//左边,左子结点
build(m+1,r,rt<<1|1);//右边,右子结点
pushup(rt);
}
void update(int l,int r,int rt){
if(l==r){
tree[rt]+=C;
return;
}
int m=(l+r)>>1;
if(L<=m)update(l,m,rt<<1);//更新在左子树
else update(m+1,r,rt<<1|1);//更新在右子树
pushup(rt);//子结点已经更新,该结点也需要更新
}
int query(int l,int r,int rt){
if(l>=L&&r<=R){
return tree[rt];
}
int m=(l+r)>>1;
int ans=0;//根据题意更新ans最小值
if(L<=m)ans=ans+query(l,m,rt<<1);
if(m<R)ans=ans+query(m+1,r,rt<<1|1);
return ans;
}
int main(){
int t;
cin>>t;
for(int j=1;j<=t;j++){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&A[i]);
}
build(1,n,1);
//for(int i=1;i<=3*n;i++)printf("%d ",tree[i]);
printf("Case %d:\n",j);
while(1){
char str[15];
scanf("%s",str);
if(str[0]=='E')break;
else if(str[0]=='Q'){
scanf("%d%d",&L,&R);
cout<<query(1,n,1)<<endl;
}else if(str[0]=='A'){
scanf("%d%d",&L,&C);
update(1,n,1);
}else if(str[0]=='S'){
scanf("%d%d",&L,&C);
C=-C;
update(1,n,1);
}
}
}
return 0;
}
洛谷模板1--区间修改(加)
线段树+区间修改+区间查询
传送门
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define debug printf("%d %s\n",__LINE__,__FUNCTION__)
#define lson l,m,rt<<1//左儿子
#define rson m+1,r,rt<<1|1//右儿子
using namespace std;
const int N=100005;
ll n,m,sum[N<<2],add[N<<2];
ll R,L,C;
il ll read(){//快速读入数字
ll a=0;char x=getchar();bool f=0;
while((x<'0'||x>'9')&&x!='-')x=getchar();
if(x=='-')x=getchar(),f=1;
while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
return f?-a:a;
}
il void pushup(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
il void pushdown(int l,int r,int rt){
ll m=r-l+1;
if(add[rt]){
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
sum[rt<<1]+=add[rt]*(m-(m>>1));
sum[rt<<1|1]+=add[rt]*(m>>1);
add[rt]=0;
}
}
il void build(int l,int r,int rt){
add[rt]=0;
if(l==r){
sum[rt]=read();
return;
}
int m=l+r>>1;
build(lson),build(rson);
pushup(rt);
}
il void update(int l,int r,int rt){
if(L<=l&&R>=r){
add[rt]+=C;
sum[rt]+=(ll)C*(r-l+1);
return ;
}
pushdown(l,r,rt);
int m=l+r>>1;
if(L<=m)update(lson);
if(m<R)update(rson);
pushup(rt);
}
il ll query(int l,int r,int rt){
if(L<=l&&R>=r)return sum[rt];
pushdown(l,r,rt);
int m=l+r>>1;
ll ret=0;
if(L<=m)ret+=query(lson);
if(m<R)ret+=query(rson);
return ret;
}
int main(){
n=read(),m=read();
build(1,n,1);
while(m--){
ll u=read();
if(u==1){
L=read(),R=read(),C=read();
update(1,n,1);
}
else {
L=read(),R=read();
printf("%lld\n",query(1,n,1));
}
}
return 0;
}
牛客竞赛区间和
传送门
很奇怪,我用之前的模板在hdu里答题都过了,但是在牛客重新套用这个模板竟然过不了?为什么
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define debug printf("%d %s\n",__LINE__,__FUNCTION__)
#define lson l,m,rt<<1//左儿子
#define rson m+1,r,rt<<1|1//右儿子
using namespace std;
const int N=1e6+5;
ll n,m,sum[N<<2],add[N<<2];
ll R,L,C;
il ll read(){//快速读入数字
ll a=0;char x=getchar();bool f=0;
while((x<'0'||x>'9')&&x!='-')x=getchar();
if(x=='-')x=getchar(),f=1;
while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
return f?-a:a;
}
il void pushup(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
il void pushdown(int l,int r,int rt){
ll m=r-l+1;
if(add[rt]){
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
sum[rt<<1]+=add[rt]*(m-(m>>1));
sum[rt<<1|1]+=add[rt]*(m>>1);
add[rt]=0;
}
}
il void build(int l,int r,int rt){
add[rt]=0;
if(l==r){
sum[rt]=read();
return;
}
int m=l+r>>1;
build(lson),build(rson);
pushup(rt);
}
il void update(int l,int r,int rt){
if(L<=l&&R>=r){
add[rt]+=C;
sum[rt]+=(ll)C*(r-l+1);
return ;
}
pushdown(l,r,rt);
int m=(l+r)>>1;
if(L<=m)update(lson);
if(m<R)update(rson);
pushup(rt);
}
il ll query(int l,int r,int rt){
if(L<=l&&R>=r)return sum[rt];
pushdown(l,r,rt);
int m=l+r>>1;
ll ret=0;
if(L<=m)ret+=query(lson);
if(m<R)ret+=query(rson);
return ret;
}
int main(){
n=read(),m=read();
build(1,n,1);
while(m--){
ll u=read();
if(u==1){
L=read(),R=L,C=read();
update(1,n,1);
}
else {
L=read(),R=read();
printf("%lld\n",query(1,n,1));
}
}
return 0;
}
洛谷模板2--区间修改(乘)
线段树+区间修改+区间查询
传送门
#include<bits/stdc++.h>
#define LL long long
#define L(x) x<<1 //左儿子 x*2
#define R(x) x<<1|1 //右儿子 x*2+1
const int maxn =1e5+5;
using namespace std;
LL n,m,num[maxn];
LL mod; //膜数
inline LL read() {
LL x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9') f=(ch=='-')?-1:1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*f;
}
struct T {
LL l,r;
LL sum,add,mul;
} tree[maxn<<2];//注意开long long 和四倍空间
inline void update(LL p) {
tree[p].sum=(tree[L(p)].sum+tree[R(p)].sum)%mod;
return;
}
inline void spread(LL p) {
LL mid=(tree[p].l+tree[p].r)>>1;
if(tree[p].mul!=1) {
tree[L(p)].mul=(tree[L(p)].mul*tree[p].mul)%mod;
tree[R(p)].mul=(tree[R(p)].mul*tree[p].mul)%mod;
tree[L(p)].add=(tree[L(p)].add*tree[p].mul)%mod;
tree[R(p)].add=(tree[R(p)].add*tree[p].mul)%mod;
tree[L(p)].sum=(tree[L(p)].sum*tree[p].mul)%mod;
tree[R(p)].sum=(tree[R(p)].sum*tree[p].mul)%mod;
tree[p].mul=1;
}
if(tree[p].add) {
tree[L(p)].add=(tree[L(p)].add+tree[p].add)%mod;
tree[R(p)].add=(tree[R(p)].add+tree[p].add)%mod;
tree[L(p)].sum=(tree[L(p)].sum+tree[p].add*(mid-tree[p].l+1))%mod;
tree[R(p)].sum=(tree[R(p)].sum+tree[p].add*(tree[p].r-mid))%mod;//tree[p].r-mid不加1
tree[p].add=0;
}
return;
}
inline void build(LL l,LL r,LL p) {//建树
tree[p].l=l,tree[p].r=r,tree[p].mul=1;
if(l==r) {
tree[p].sum=num[l];
tree[p].mul=1;
return;
}
LL mid=(tree[p].l+tree[p].r)>>1;
build(l,mid,L(p));
build(mid+1,r,R(p));
update(p);
return;
}
inline void change1(LL l,LL r,LL p,LL v) {//区间增值
if(tree[p].l==l&&tree[p].r==r) {
tree[p].add=(tree[p].add+v)%mod;
tree[p].sum=(tree[p].sum+v*(r-l+1))%mod;
return;
}
spread(p);
LL mid=(tree[p].l+tree[p].r)>>1;
if(r<=mid) change1(l,r,L(p),v);
else if(l>mid) change1(l,r,R(p),v);
else change1(l,mid,L(p),v),change1(mid+1,r,R(p),v);
update(p);
return;
}
inline void change2(LL l,LL r,LL p,LL v) {//区间乘法
if(tree[p].l==l&&tree[p].r==r) {
tree[p].mul=(tree[p].mul*v)%mod;
tree[p].sum=(tree[p].sum*v)%mod;
tree[p].add=(tree[p].add*v)%mod;
return;
}
spread(p);
LL mid=(tree[p].l+tree[p].r)>>1;
if(r<=mid) change2(l,r,L(p),v);
else if(l>mid) change2(l,r,R(p),v);
else change2(l,mid,L(p),v),change2(mid+1,r,R(p),v);
update(p);
return;
}
inline LL ask_sum1(LL l,LL r,LL p) {//区间和
if(tree[p].l==l&&tree[p].r==r) {
return tree[p].sum%mod;
}
spread(p);
LL mid=(tree[p].l+tree[p].r)>>1;
if(r<=mid) return ask_sum1(l,r,L(p))%mod;
else if(l>mid) return ask_sum1(l,r,R(p))%mod;
else return (ask_sum1(l,mid,L(p))%mod+ask_sum1(mid+1,r,R(p))%mod)%mod;
}
inline LL ask_sum2(LL l,LL r,LL p) {//区间平方和
if(tree[p].l==tree[p].r) {
return tree[p].sum*tree[p].sum;
}
spread(p);
LL mid=(tree[p].l+tree[p].r)>>1;
if(r<=mid) return ask_sum2(l,r,L(p));
else if(l>mid) return ask_sum2(l,r,R(p));
else return ask_sum2(l,mid,L(p))+ask_sum2(mid+1,r,R(p));
}
LL opt,l,r,v;
int main() {
n=read(),m=read(),mod=read();
for(int i=1; i<=n; i++) num[i]=read();
build(1,n,1);
while(m--) {
opt=read();
if(opt==3) {
l=read(),r=read();
printf("%lld\n",ask_sum1(l,r,1)%mod);//询问区间和
}
if(opt==4) {
l=read(),r=read();
printf("%lld\n",ask_sum2(l,r,1)%mod);//询问区间平方和
}
if(opt==1) {
l=read(),r=read(),v=read();
change2(l,r,1,v);//区间乘
}
if(opt==2) {
l=read(),r=read(),v=read();
change1(l,r,1,v);//区间加
}
}
return 0;
}