[kuangbin]专题七 线段树 部分题解(持续更新)

题目链接 [kuangbin带你飞]专题七 线段树

线段树,从入门到模板,呵呵呵~

线段树是acm里一个基本的题型啰,一般用于区间的问题

首先模板:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 1e9+7
#define ffr(i,a,b)  for(int i=a;i<b;i++)
#define mem(a,b)  memset( a,b,sizeof a)
#define Max(x,y)  y>x? x=y: x=x
const int maxn=1e5+7;
struct node{
    int l,r;
    ll lazy,sum;
    void update(ll x){
        sum+=x*(r-l+1); // 更新懒结点,一般的题目只要修改这儿就行了
        lazy+=x;
    }
}tree[maxn*4];
int a[maxn];
void push_up(int x){
    tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum; /// 根据题目要求
}
void push_down(int x){
    int lazytp=tree[x].lazy;
    if(lazytp){
        tree[x<<1].update(lazytp);
        tree[x<<1|1].update(lazytp);
        tree[x].lazy=0;
    }
}
void built(int x,int l,int r){
    tree[x]=node{l,r,0,0};
    if(l==r){
        tree[x].sum=a[l];
    }
    else{
        int mid=(l+r)>>1;
        built(x<<1 ,l ,mid );
        built(x<<1|1 ,mid+1 ,r );
        push_up(x);
    }
}
void update(int x,int l,int r,int val){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        tree[x].update(val);
    }
    else{
        push_down(x);
        int mid=(L+R)>>1;
        if(mid>=l)
        update(x<<1,l,r,val);
        if(mid<r)
        update(x<<1|1,l,r,val);
        push_up(x);
    }
}
ll query(int x,int l,int r){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        return tree[x].sum; /// 根据题目要求
    }
    else{
        push_down(x);
        ll ans=0;
        int mid=(L+R)>>1;
        if(mid>=l)
        ans+=query(x<<1,l,r);
        if(mid<r)
        ans+=query(x<<1|1,l,r);
        push_up(x);
        return ans;
    }
}
int main(){
    std::ios::sync_with_stdio(false);
    int n,q;
    cin>>n>>q;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    built(1,1,n);
    while(q--){
        int c,l,r,k;
        cin>>c>>l>>r;
        if(c==1){
            cin>>k;
            update(1,l,r,k);
        }
        else{
            cout<<query(1,l,r)<<endl;
        }
    }
    return 0;
}

加注释的地方就是一般要改的地方啰。

A.

套模板呗,这题懒标记都不要,单点更新,所以我们可以套模板

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 1e9+7
#define ffr(i,a,b)  for(int i=a;i<b;i++)
#define mem(a,b)  memset( a,b,sizeof a)
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++)
#define Max(x,y) y>x?x=y:x=x
char buf[(1 << 22)], *p1 = buf, *p2 = buf;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();return x * f;
}
const int maxn=5e4+7;
#define read(x) x=read()
int n;
int f[maxn];
struct node{
    int l,r;
    ll lazy,sum;
    void update(ll x){
        sum+=x*(r-l+1);
        lazy+=x;
    }
}tree[maxn*4];
void push_up(int x){
    tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;
}
void push_down(int x){
    int lazytp=tree[x].lazy;
    if(lazytp){
        tree[x<<1].update(lazytp);
        tree[x<<1|1].update(lazytp);
        tree[x].lazy=0;
    }
}
int a[maxn];
void built(int x,int l,int r){
    tree[x]=node{l,r,0,0};
    if(l==r){
        tree[x].sum=f[l];
    }
    else{
        int mid=(l+r)>>1;
        built(x<<1 ,l ,mid );
        built(x<<1|1 ,mid+1 ,r );
        push_up(x);
    }
}
void update(int x,int l,int r,int val){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        tree[x].update(val);
    }
    else{
        push_down(x);
        int mid=(L+R)>>1;
        if(mid>=l)
        update(x<<1,l,r,val);
        if(mid<r)
        update(x<<1|1,l,r,val);
        push_up(x);
    }
}
ll query(int x,int l,int r){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        return tree[x].sum;
    }
    else{
        push_down(x);
        ll ans=0;
        int mid=(L+R)>>1;
        if(mid>=l)
        ans+=query(x<<1,l,r);
        if(mid<r)
        ans+=query(x<<1|1,l,r);
        push_up(x);
        return ans;
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    int t,ca=0;
    cin>>t;
    while(t--){
        ca++;
        mem(f,0);
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>f[i];
        }
        built(1,1,n);
        string ts;
        int x,y;
        cout<<"Case "<<ca<<":"<<endl;
        while(cin>>ts && ts!="End"){
            cin>>x>>y;
            if(ts=="Query"){
                cout<<query(1,x,y)<<endl;
            }
            else if(ts=="Add"){
                update(1,x,x,y);
            }
            else if(ts=="Sub"){
                update(1,x,x,-y);
            }
        }
    }
    return 0;
}
View Code

B.

同样套模板,不要懒标记的,只要更新保存最大值就行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 1e9+7
#define ffr(i,a,b)  for(int i=a;i<b;i++)
#define mem(a,b)  memset( a,b,sizeof a)
#define Max(x,y) y>x?x=y:x=x
const int maxn=2e5+7;
int n,m;
int f[maxn];
struct node{
    int l,r;
    ll ma;
}tree[maxn*4];
int a[maxn];
void push_up(int x){
    tree[x].ma=max(tree[x<<1].ma,tree[x<<1|1].ma);
}
void built(int x,int l,int r){
    tree[x]=node{l,r,-1};
    if(l==r){
        tree[x].ma=f[l];
    }
    else{
        int mid=(l+r)>>1;
        built(x<<1 ,l ,mid );
        built(x<<1|1 ,mid+1 ,r );
        push_up(x);
    }
}
void update(int x,int l,int r,int val){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        tree[x].ma=val;
    }
    else{
        int mid=(L+R)>>1;
        if(mid>=l)
        update(x<<1,l,r,val);
        if(mid<r)
        update(x<<1|1,l,r,val);
        push_up(x);
    }
}
ll query(int x,int l,int r){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        return tree[x].ma;
    }
    else{
        ll ans=0;
        int mid=(L+R)>>1;
        if(mid>=l)
        ans=max(ans,query(x<<1,l,r));
        if(mid<r)
        ans=max(ans,query(x<<1|1,l,r) );
        return ans;
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    while(cin>>n>>m){
        for(int i=1;i<=n;i++){
            cin>>f[i];
        }
        built(1,1,n);
        char c;
        int x,y;
        while(m--){
            cin>>c>>x>>y;
            if(c=='Q'){
                cout<<query(1,x,y)<<endl;
            }
            else if(c=='U'){
                update(1,x,x,y);
            }
        }
    }
    return 0;
}
View Code

C.

模板,几乎没改

#include<bits/stdc++.h>
#include<iostream>
using namespace std;
typedef long long ll;
#define inf 1e9+7
#define ffr(i,a,b)  for(int i=a;i<b;i++)
#define mem(a,b)  memset( a,b,sizeof a)
#define Max(x,y)  y>x? x=y: x=x
const int maxn=1e5+7;
struct node{
    int l,r;
    ll lazy,sum;
    void update(ll x){
        sum+=x*(r-l+1);
        lazy+=x;
    }
}tree[maxn*4];
void push_up(int x){
    tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;
}
void push_down(int x){
    int lazytp=tree[x].lazy;
    if(lazytp){
        tree[x<<1].update(lazytp);
        tree[x<<1|1].update(lazytp);
        tree[x].lazy=0;
    }
}
int a[maxn];
void built(int x,int l,int r){
    tree[x]=node{l,r,0,0};
    if(l==r){
        tree[x].sum=a[l];
    }
    else{
        int mid=(l+r)>>1;
        built(x<<1 ,l ,mid );
        built(x<<1|1 ,mid+1 ,r );
        push_up(x);
    }
}
void update(int x,int l,int r,int val){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        tree[x].update(val);
    }
    else{
        push_down(x);
        int mid=(L+R)>>1;
        if(mid>=l)
        update(x<<1,l,r,val);
        if(mid<r)
        update(x<<1|1,l,r,val);
        push_up(x);
    }
}
ll query(int x,int l,int r){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        return tree[x].sum;
    }
    else{
        push_down(x);
        ll ans=0;
        int mid=(L+R)>>1;
        if(mid>=l)
        ans+=query(x<<1,l,r);
        if(mid<r)
        ans+=query(x<<1|1,l,r);
        push_up(x);
        return ans;
    }
}
int main(){
    std::ios::sync_with_stdio(false);
    int n,q;
    while(cin>>n>>q){
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        built(1,1,n);
        while(q--){
                char c;
            int l,r,k;
            cin>>c>>l>>r;
            if(c=='C'){
                cin>>k;
                update(1,l,r,k);
            }
            else{
                cout<<query(1,l,r)<<endl;
            }
        }
    }
    return 0;
}
View Code

D.

离散化++明天一定写。。0.0

E.

建树时每个点都是1,需要修改一下懒标记,把区间加懒标记的值  变成 区间变为懒标记乘区间的值,

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 1e9+7
#define ffr(i,a,b)  for(int i=a;i<b;i++)
#define mem(a,b)  memset( a,b,sizeof a)
#define Max(x,y) y>x?x=y:x=x
int n,q;
const int maxn=1e5+7;
struct node{
    int l,r;
    ll lazy,sum;
    void update(ll x){
        sum=x*(r-l+1);
        lazy=x;
    }
}tree[maxn*4];
void push_up(int x){
    tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;
}
void push_down(int x){
    int lazytp=tree[x].lazy;
    if(lazytp){
        tree[x<<1].update(lazytp);
        tree[x<<1|1].update(lazytp);
        tree[x].lazy=0;
    }
}
void built(int x,int l,int r){
    tree[x]=node{l,r,0,0};
    if(l==r){
        tree[x].sum=1;
    }
    else{
        int mid=(l+r)>>1;
        built(x<<1 ,l ,mid );
        built(x<<1|1 ,mid+1 ,r );
        push_up(x);
    }
}
void update(int x,int l,int r,int val){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        tree[x].update(val);
    }
    else{
        push_down(x);
        int mid=(L+R)>>1;
        if(mid>=l)
        update(x<<1,l,r,val);
        if(mid<r)
        update(x<<1|1,l,r,val);
        push_up(x);
    }
}
ll query(int x,int l,int r){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        return tree[x].sum;
    }
    else{
        push_down(x);
        ll ans=0;
        int mid=(L+R)>>1;
        if(mid>=l)
        ans+=query(x<<1,l,r);
        if(mid<r)
        ans+=query(x<<1|1,l,r);
        push_up(x);
        return ans;
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    int t,ca=0;
    cin>>t;
    while(t--){
        ca++;
        cin>>n>>q;
        built(1,1,n);
        for(int i=0,x,y,z;i<q;i++){
            cin>>x>>y>>z;
            update(1,x,y,z);
        }
        cout<<"Case "<<ca<<": The total value of the hook is "<<query(1,1,n)<<"."<<endl;
    }
    return 0;
}
View Code

G.

和B的做法一样,分别保存查询最大最小值就行了,但是,好像要输入输出优化,用c++应该不会超时,于是又敲了一遍RMQ

扫描二维码关注公众号,回复: 5766838 查看本文章

线段树

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
#define inf 1e9+7
#define ffr(i,a,b)  for(int i=a;i<b;i++)
#define mem(a,b)  memset( a,b,sizeof a)
#define Max(x,y) y>x?x=y:x=x
int n,m;
const int maxn=5e4+7;
ll a[maxn];
struct node{
    int l,r;
    ll maxh,minh;
}tree[maxn*4];
void push_up(int x){
    tree[x].maxh=max(tree[x<<1].maxh,tree[x<<1|1].maxh);
    tree[x].minh=min(tree[x<<1].minh,tree[x<<1|1].minh);
}
void built(int x,int l,int r){
    tree[x]=node{l,r,-inf,inf};
    if(l==r){
        tree[x].minh=tree[x].maxh=a[l];
    }
    else{
        int mid=(l+r)>>1;
        built(x<<1 ,l ,mid );
        built(x<<1|1 ,mid+1 ,r );
        push_up(x);
    }
}
ll query1(int x,int l,int r){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        return tree[x].maxh;
    }
    else{
        ll ans=0;
        push_up(x);
        int mid=(L+R)>>1;
        if(mid>=l)
        ans=max(ans,query1(x<<1,l,r));
        if(mid<r)
        ans=max(ans,query1(x<<1|1,l,r));
        return ans;
    }
}
ll query2(int x,int l,int r){
    int L=tree[x].l,R=tree[x].r;
    if(l<=L&&R<=r){
        return tree[x].minh;
    }
    else{
        ll ans=inf;
        push_up(x);
        int mid=(L+R)>>1;
        if(mid>=l)
        ans=min(ans,query2(x<<1,l,r));
        if(mid<r)
        ans=min(ans,query2(x<<1|1,l,r));
        return ans;
    }
}
ll query(int x,int l,int r){
    return query1(x,l,r)-query2(x,l,r);
}
int main()
{
    scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%lld",a+i);
        }
        built(1,1,n);
        int l,r;
        while(m--){
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(1,l,r) );
        }
    return 0;
}
View Code

RMQ

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
#define inf 1e9+7
#define ffr(i,a,b)  for(int i=a;i<b;i++)
#define mem(a,b)  memset( a,b,sizeof a)
#define Max(x,y) y>x?x=y:x=x
int n,m;
const int maxn=5e4+7;
ll a[maxn];
ll st1[maxn][20];
ll st2[maxn][20]={inf};
void RMQ1(){
    for(int j=1;j<=20;j++){
        for(int i=1;i<=n;i++){
            if(i+(1<<j)-1<=n){
                st1[i][j]=max(st1[i][j-1],st1[i+(1<<(j-1)) ][j-1]);
            }
        }
    }
}
void RMQ2(){
    for(int j=1;j<=20;j++){
        for(int i=1;i<=n;i++){
            if(i+(1<<j)-1<=n){
                st2[i][j]=min(st2[i][j-1],st2[i+(1<<(j-1)) ][j-1]);
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",a+i);
        st1[i][0]=st2[i][0]=a[i];
    }
    RMQ1();
    RMQ2();
    while(m--){
        int l,r;
        scanf("%d%d",&l,&r);
        int k=log2(r-l+1);
        ll a=max( st1[l][k],st1[r-(1<<k)+1][k] );
        ll b=min( st2[l][k],st2[r-(1<<k)+1][k] );
        printf("%lld\n", a-b );
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/37kiazz73/p/10651470.html
今日推荐