线段树的模板(更新ing)

来源:互联网 发布:辩论赛网络的利与弊 编辑:程序博客网 时间:2024/06/06 13:06

1.单点修改(增加/减少)+区间求和
例题:计蒜客 斑点蛇(敌兵布阵)
第一行一个正整数 N(N≤50000)表示这条斑点蛇长度为 N 厘米,接下来有 N 个正整数,第i 个正整数 a_i

​​ 代表第 i 个斑点蛇第 i 厘米开始时有 a_i​个斑点( 1≤ai​≤50)。

接下来每行有一条命令,命令有4 种形式:

(1) Add i j,i 和 j 为正整数,表示第 i 厘米增加 j 个斑点(j 不超过 30);

(2) Sub i j,i 和 j 为正整数,表示第 i 厘米减少 j 个斑点(j 不超过 30);

(3) Query i j,i 和 j 为正整数,i≤j,表示询问第 i 到第 j 厘米的斑点总数(包括第 i 厘米和第 j 厘米);

(4) End 表示结束,这条命令在每组数据最后出现;

最多有 40000 条命令。

输出格式

对于每个 Query 询问,输出一个整数并回车,表示询问的段中的总斑点数,这个数保证在int范围内。

#include<bits/stdc++.h>using namespace std;int n,s[200004]={0},a[50001];void build(int num,int l,int r){    if(l==r)    {       s[num]=a[l];        return;    }    int mid=(l+r)/2;    build(num*2,l,mid);    build(num*2+1,mid+1,r);    s[num]=s[num*2]+s[num*2+1];}void modify(int p,int l,int r,int x,int v){//吧父亲的信息传给儿子    s[p]+=v;    if(l==r) return;//叶结点则退  出    int mid=(l+r)/2;    if(x<=mid)//判断x在左儿子还是右儿子        modify(p*2,l,mid,x,v);    else        modify(p*2+1,mid+1,r,x,v);}int query(int p,int l,int r,int x,int y){    if(x<=l&&r<=y) return s[p];//若该结点被所查询区间包含    int mid=(l+r)/2;    int res=0;    if(x<=mid) res+=query(p*2,l,mid,x,y);    if(y>mid) res+=query(p*2+1,mid+1,r,x,y);    return res;}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)        scanf("%d",&a[i]);    build(1,1,n);    string s;    for(;;){        cin>>s;    if(s=="Add"){        int i,j;        cin>>i>>j;        modify(1,1,n,i,j);    }    else if(s=="Sub"){        int i,j;        cin>>i>>j;        modify(1,1,n,i,0-j);    }else if(s=="Query"){        int i,j;        cin>>i>>j;        cout<<query(1,1,n,i,j)<<endl;    }    else if(s=="End"){      break;          }    }    return 0;}

裸的套模板就行
写这题的时候才发现……计蒜客没讲怎么建树2333
2.单点覆盖+区间最值
习题:最甜的苹果
(I HATe it)
又找到原题了……

题目描述:很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。 这让很多学生很反感。 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。输入:  本题目包含多组测试,请处理到文件结束。   在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。   学生ID编号分别从1编到N。   第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。   接下来有M行。每一行有一个字符 C (只取'Q''U') ,和两个正整数A,B。   当C'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。   当C'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。 输出:  对于每一次询问操作,在一行里面输出最高成绩。 样例输入:  5 7 1 2 3 4 5 Q 1 5 U 3 6 Q 3 4 Q 4 5 U 2 9 Q 1 5 Q 2 4样例输出:  5 6 5 9 9  这次要建的是最值树,建树和查询,修改的子函数都要改用结构体储存最值(我为什么不直接用数组……)还有区间修改……慢慢补
#include<bits/stdc++.h>using namespace std;const int maxn=200001;struct tree{    int maxx=0;}s[maxn*4+10];int n,m;void build(int num,int l,int r){    if(l==r){        cin>>s[num].maxx;        return;    }    int mid=(l+r)>>1;    build(num*2,l,mid);    build(num*2+1,mid+1,r);    s[num].maxx=max(s[num*2].maxx,s[num*2+1].maxx);//最值建树}void modify(int p,int l,int r,int x,int v){    if(l==r&&l==x) {s[p].maxx=v;return;}    //是叶结点则退出    int mid=(l+r)/2;    if(x<=mid){//是在儿子还是女儿        modify(p*2,l,mid,x,v);//左    }    else        modify(p*2+1,mid+1,r,x,v);    s[p].maxx=max(s[p*2].maxx,s[p*2+1].maxx);//更新父亲结点}int query(int p,int l,int r,int x,int y){    if(x<=l&&r<=y){        return s[p].maxx;    }    int mid=(l+r)/2,res=0;    if(x<=mid) res=max(res,query(p*2,l,mid,x,y));    if(y>mid) res=max(res,query(p*2+1,mid+1,r,x,y));    return res;}int main(){    cin>>n>>m;    build(1,1,n);    char c;    int x,y;    while(m--){        cin>>c>>x>>y;        if(c=='Q')        {                cout<<query(1,1,n,x,y)<<endl;        }else if(c=='U'){            modify(1,1,n,x,y);        }    }    return 0;}
原创粉丝点击