ACM入门之线段树习题

Posted 辉小歌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM入门之线段树习题相关的知识,希望对你有一定的参考价值。

目录

1275. 最大数【单点修改 区间最大】

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*2+10;
struct nodeint l,r,v;tr[N*4];
int m,p;
void build(int u,int l,int r)//建树

    tr[u]=l,r;
    if(l==r) return;
    int mid=tr[u].l+tr[u].r>>1;
    build(u*2,l,mid);
    build(u*2+1,mid+1,r);

void pushup(int u)

    tr[u].v=max(tr[u*2].v,tr[u*2+1].v);

int query(int u,int l,int r)

    if(tr[u].l>=l&&tr[u].r<=r) return tr[u].v;//包含
    else
    
        int v=0,mid=(tr[u].l+tr[u].r)/2;
        if(l<=mid) v=max(v,query(u*2,l,r));//左边有交集
        if(r>=mid+1) v=max(v,query(u*2+1,l,r));//右边有交集
        return v;
    

void modify(int u,int x,int v)
//u是根,x是位置,v是值

    if(tr[u].l==x&&tr[u].r==x) tr[u].v=v;//叶子
    else
    
        int mid=tr[u].l+tr[u].r>>1;
		if(x<=mid) modify(u*2,x,v);
		else modify(u*2+1,x,v);
		pushup(u);
    

int main(void)

    cin>>m>>p;
    build(1,1,m);
    int last=0,n=0;
    for(int i=0;i<m;i++)
    
        char op; cin>>op;
        if(op=='Q')
        
            int x; cin>>x;
            last=query(1,n-x+1,n);
            cout<<last<<endl;
        else
        
            int x; cin>>x;
            modify(1,n+1,(1ll*x+last)%p);
            n++;
        
    
    return 0;

245. 你能回答这些问题吗【单点修改 / 区间内的最大连续字段】

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
struct node

    int l,r;
    int sum,tmax,lmax,rmax;
    //sum: 区间和
	//tmax:整个区间的最大子段和
	//lmax:从左端点起的向右的最大子段和
	//rmax:从右端点起的向左的最大子段和
tr[N*4];
int a[N],n,m;
void push(node& a,node& l,node& r)

    a.sum=l.sum+r.sum;
    a.tmax=max(l.tmax,r.tmax,l.rmax+r.lmax,l.sum+r.lmax,r.sum+l.rmax,);
    a.lmax=max(l.lmax,l.sum+r.lmax);
    a.rmax=max(r.rmax,r.sum+l.rmax);

void pushup(int u)

    push(tr[u],tr[u*2],tr[u*2+1]);

void build(int u,int l,int r)

    if(l==r) tr[u]=l,r,a[l],a[l],a[l],a[l];
    else
    
        tr[u]=l,r;
        int mid=l+r>>1;
        build(u*2,l,mid),build(u*2+1,mid+1,r);
        pushup(u);
    

void modify(int u,int x,int v)

    if(tr[u].l==x&&tr[u].r==x) 
    
        tr[u]=x,x,v,v,v,v;
    else
    
        int mid=(tr[u].l+tr[u].r)/2;
        if(mid>=x) modify(u*2,x,v);
        else modify(u*2+1,x,v);
        pushup(u);
    

node query(int u,int l,int r)

    if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
    else 
    
        int mid=(tr[u].l+tr[u].r)/2;
        if(mid>=r) return query(u*2,l,r);
        else if(l>mid) return query(u*2+1,l,r);
        else
        
            auto left=query(u*2,l,r);
            auto right=query(u*2+1,l,r);
            node res;
            push(res,left,right);
            return res;
        
    

int main(void)

    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    build(1,1,n);
    for(int i=0;i<m;i++)
    
        int op,x,y; cin>>op>>x>>y;
        if(op==1)
        
            if(x>y) swap(x,y);
            auto temp=query(1,x,y);
            cout<<temp.tmax<<endl;
        else modify(1,x,y);
    
    return 0;

246. 区间最大公约数【区间修改 区间最大公约数】



上述题解的原处

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5*5+10;
LL gcd(LL a,LL b)return b?gcd(b,a%b):a;
struct node

    int l,r;
    LL sum,d;//sum区间总和,d区间最大公约数
tr[N*4];
LL n,m,a[N];
void push(node& u,node& l,node& r)

    u.sum=l.sum+r.sum;
    u.d=gcd(l.d,r.d);

void pushup(int u)

    push(tr[u],tr[u*2],tr[u*2+1]);

void build(int u,int l,int r)

    if(l==r)
    
        LL b=a[l]-a[l-1];
        tr[u]=l,r,b,b;
    else
    
        tr[u]=l,r;
        int mid=l+r>>1;
        build(u*2,l,mid),build(u*2+1,mid+1,r);
        pushup(u);
    

void modify(int u,int x,LL c)

    if(tr[u].l==x&&tr[u].r==x)
    
        tr[u].sum+=c,tr[u].d+=c;
        return;
    
    else
    
        int mid=(tr[u].l+tr[u].r)/2;
        if(mid>=x) modify(u*2,x,c);
        else modify(u*2+1,x,c);
        pushup(u);
    

node query(int u,int l,int r)

    if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
    else
    
        int mid=(tr[u].l+tr[u].r)/2;
        if(mid>=r) return query(u*2,l,r);
        else if(l>=mid+1) return query(u*2+1,l,r);
        else
        
            auto left=query(u*2,l,r);
            auto right=query(u*2+1,l,r);
            node res;
            push(res,left,right);
            return res;
        
    

int main(void)

    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    build(1,1,n);
    for(int i=1;i<=m;i++)
    
        char op; cin>>op;
        if(op=='C')
        
            LL l,r,d; cin>>l>>r>>d;
            modify(1,l,d);
            if(r+1<=n) modify(1,r+1,-d);
        else
        
            int l,r; cin>>l>>r;
            node right=0,0,0,0;
            auto left=query(1,1,l);
            if(l+1<=n) right=query(1,l+1,r);
            printf("%lld\\n",labs(gcd(left.sum,right.d)));
        
    
    return 0;

P3372 【模板】线段树 1【区间修改,区间查询】

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5+10;
struct node

    int l,r;
    LL sum,add;
tr[N*4];
LL a[N],n,m;
void pushup(int u)

    tr[u].sum=tr[u*2].sum+tr[u*2+1].sum;

void pushdown(int u)//根节点更新,子结点

    auto &ans=tr[u];
    auto &l=tr[u*2];
    auto &r=tr[u*2+1];
    if(ans.add)
    
        l.sum+=(l.r-l.l+1)*ans.add;
        r.sum+=(r.r-r.l+1)以上是关于ACM入门之线段树习题的主要内容,如果未能解决你的问题,请参考以下文章

ACM入门之树状数组

线段树入门之单点更新

线段树入门之成段更新

POJ-3667 线段树区间合并入门题

ACM入门之图论习题

ACM入门之树状数组习题