线段树模板及专题合集-----不断更新中

之前学过一段时间的线段树,后来就没有再做了,上次比赛做到几道题居然都是线段树,而且渐渐发现线段树的适用性之广和重要性,而且之前学的不全面,于是决定重现学一遍线段树,顺便改一下之前的代码风格

一.单点更新

最典型的最基础的题目就是敌兵布阵了,题意大概是给n个数,然后3种操作:某个点的数加上x,某个点的数减去x,求[x,y]区间所有数的和。前两种操作都一样,只不过减去x相当于加上-x

先贴一段以前写的搓代码:

#include<stdio.h>
#include<string.h>
const int MAXNODE = 50005;
typedef struct NODE{
    int left,right;
    int num;
}Node;
int ans=0;
int num[50010];
Node node[140000];
void creattree(int i,int left,int right)
{
    node[i].left=left;
    node[i].right=right;
    if(left==right)
    {
        node[i].num=num[right];
        return;
    }
    creattree(i*2,left,(left+right)/2);
    creattree(i*2+1,(left+right)/2+1,right);
    node[i].num+=node[i*2].num+node[i*2+1].num;
}
void sum(int left,int right,int i)
{
    if(node[i].left==left&&node[i].right==right)
    {
        ans+=node[i].num;
        return;
    }
    else{
        int mid=(node[i].left+node[i].right)/2;
        if(mid>=right) sum(left,right,i*2);
        else if(mid<left) sum(left,right,i*2+1);
        else{
            sum(left,mid,i*2);
            sum(mid+1,right,i*2+1);
        }
    }
}
void add(int left,int right,int i,int k)
{
    node[i].num+=k;
    if(node[i].left==left&&node[i].right==right)
    {
        return;
    }
    else{
    int mid=(node[i].left+node[i].right)/2;
    if(mid>=right) add(left,right,i*2,k);
    else if(mid<left) add(left,right,i*2+1,k);}
}
int main()
{
    char s[10];
    int t;
    while(scanf("%d",&t)!=EOF)
    {
        for(int Case=1;Case<=t;Case++)
        {
            memset(num,0,sizeof(0));
            int n;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&num[i]);
            }
            creattree(1,1,n);
            printf("Case %d:\n",Case);
            while( scanf("%s",s))
            {
                int a,b;

                if(s[0]=='E') break;
                scanf("%d%d",&a,&b);
                if(s[0]=='A') add(a,a,1,b);
                else if(s[0]=='S') add(a,a,1,-b);
                else if(s[0]=='Q')
                {
                    ans=0;
                    sum(a,b,1);
                    printf("%d\n",ans);
                }
            }
        }
    }
    return 0;
}

接着是最新更新的代码风格:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 5e5+5;
int sum[maxn*4];
int num[maxn];
void up(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int rt,int l,int r){
    if(l==r) {sum[rt]=num[l];return;}
    int m=(l+r)>>1;
    build(rt<<1,l,m);
    build(rt<<1|1,m+1,r);
    up(rt);
}
void update(int p,int add,int rt,int l,int r){
    if(l==r) {
        sum[rt]+=add;
        return;
    }
    int m=(l+r)>>1;
    if(p>m) update(p,add,rt<<1|1,m+1,r);
    else update(p,add,rt<<1,l,m);
    up(rt);
}
int query(int L,int R,int rt,int l,int r){
    if(l>=L&&r<=R) return sum[rt];
    int m=(l+r)>>1;
    int ret = 0;
    if(L<=m) ret+=query(L,R,rt<<1,l,m);
    if(R>m) ret+=query(L,R,rt<<1|1,m+1,r);
    return ret;
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++){
        int n;
        memset(sum,0,sizeof(sum));
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&num[i]);
        }
        build(1,1,n);
        printf("Case %d:\n",cas);
        char s[10];
        while(scanf("%s",s)!=EOF&&strcmp(s,"End")){
            int x,y;
            scanf("%d%d",&x,&y);
            if(s[0]=='Q') printf("%d\n",query(x,y,1,1,n));
            else if(s[0]=='A') update(x,y,1,1,n);
            else if(s[0]=='S') update(x,-y,1,1,n);
        }
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-01 10:08:17

线段树模板及专题合集-----不断更新中的相关文章

Vue-小demo、小效果 合集(更新中...)

(腾讯课堂学习小demo:https://ke.qq.com/course/256052) 一.简单的指令应用 --打击灭火器 图片素材点击腾讯课堂的链接获取       html: 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="author" content="

python算法合集(更新中。。。)

一.数论算法 1.求两数的最大公约数 import sys def gcd(p, q): if q == 0: return p return gcd(q, p%q) def main(): p = int(sys.argv[1]) q = int(sys.argv[2]) print(gcd(p, q)) if __name__ == '__main__': main() 原文地址:https://www.cnblogs.com/mocuishle/p/8476632.html

线段树模板(结构体)

线段树研究了两天了,总算有了点眉目,今天也把落下的题,补了一下. 贴一份线段树模板 线段树的特点: 1. 每一层都是区间[a, b]的一个划分,记 L = b - a 2. 一共有log2L层 3. 给定一个点p,从根到叶子p上的所有区间都包含点p,且其他区间都不包含点p. 4. 给定一个区间[l; r],可以把它分解为不超过2log2 L条不相交线段的并. 总结来说:线段树最近本的应用是4点: 1.单点更新:单点替换.单点增减 2.单点询问 3.区间询问:区间之和.区间最值 4.区间更新:区间

[ACM] 线段树模板

#include<iostream> #include<cmath> using namespace std; #define maxn 200005 class Node{ public: int l,r; int add;//附加值 int sum; }node[maxn]; int getRight(int n){//获得满足2^x>=n的最小x[从0层开始,给编号获得层数] return ceil(log10(n*1.0)/log10(2.0)); } void bu

[POJ2104] 区间第k大数 [区间第k大数,可持久化线段树模板题]

可持久化线段树模板题. #include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <vector> using namespace std; int n,q,tot,a[110000]; in

hdu 4819 二维线段树模板

/* HDU 4819 Mosaic 题意:查询某个矩形内的最大最小值, 修改矩形内某点的值为该矩形(Mi+MA)/2; 二维线段树模板: 区间最值,单点更新. */ #include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 1010; int N, Q; struct Nodey { int l, r; int Max, Min; }; int locx[MAXN], l

【HDU 4819】Mosaic 二维线段树模板

二维线段树的模板题,和一维一样的思路,更新的时候注意一下细节. 存模板: /* 二维线段树模板整理 */ #include<cstdio> #include<algorithm> using namespace std; #define lson (pos<<1) #define rson (pos<<1|1) const int maxn = 805; const int INF = (1 << 30); int n; int posX[max

LA 2191电位计(线段树模板题)

线段树模板题,没啥好说的.....注意输出是case之间空一行就行.........之前一直没注意,一直wa 代码如下: #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #includ

洛谷P3372线段树模板1——线段树

题目:https://www.luogu.org/problemnew/show/P3372 线段树模板. 代码如下: #include<iostream> #include<cstdio> using namespace std; long long n,m,a[100005],ct; struct N{ long long lazy,sum; long long ls,rs; }p[200005]; void pushdown(long long cur,long long l