线段树(基础)

来源:互联网 发布:java urlencoder 加号 编辑:程序博客网 时间:2024/06/05 04:08

最近训练线段树。因为一直听说胡浩大神的线段树模版很强很优美。照着模版敲了两遍以后意思基本上能明白。也能自己写出来。但是感觉自己没有深入的思考。很颓。相比起同级不看模版自己写出来的人感觉很惭愧。但是胡浩大神真的好强啊。那个模版简直完美。我感觉就是一句废话都没有。用最简单的语言把事情描述清楚了。真的很厉害。自己有时候写代码就是逻辑关系理不清楚。有时候很简单的事情被我写的很复杂。这方面以后多注意吧。

昨天到今天看懂了两种题型。
一种是线段树的单点更新。还有一种是成段更新。
单点更新就比较好理解了。只要找出来当前节点是在左区间还是在右区间就可以进行pushup了。
成段更新我一开始想的时候觉得就是多个单点更新就行了。后来看了思路之后觉得。。哎。
他就是有一个延迟标记。对于一个需要更改的区间。其实不着急向下更新。有两种情况需要向下更新。一种是在某一次修改区间的时候需要修改的区间在当前这个有延迟标记的区间里面。还有就是查询的时候当然也要向下更新啦。有时候开闭区间还搞不是很清楚。要多注意。

Balanced Lineup

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn=50005;struct data{    int Max_n,Min_n;};struct data h[maxn<<2];int max(int p,int q){    return p>q?p:q;}int min(int p,int q){    return p>q?q:p;}void pushup(int rt){    h[rt].Max_n=max(h[rt<<1].Max_n,h[rt<<1|1].Max_n);    h[rt].Min_n=min(h[rt<<1].Min_n,h[rt<<1|1].Min_n);}void build(int l,int r,int rt){    if(l==r){        int temp;        scanf("%d",&temp);        h[rt].Max_n=temp;        h[rt].Min_n=temp;        return;    }    int m=(l+r)>>1;    build(lson);    build(rson);    pushup(rt);}int queryMax(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R){        return h[rt].Max_n;    }    int m=(l+r)>>1;    int ans=0;    if(L<=m) ans=max(ans,queryMax(L,R,lson));    if(R>m) ans=max(ans,queryMax(L,R,rson));    return ans;}int queryMin(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R){        return h[rt].Min_n;    }    int m=(l+r)>>1;    int ans=1e9+7;    if(L<=m) ans=min(ans,queryMin(L,R,lson));    if(R>m) ans=min(ans,queryMin(L,R,rson));    return ans;}int main(void){    int n,m,a,b;    //freopen("1.txt","r",stdin);    while(~scanf("%d%d",&n,&m)){        build(1,n,1);        while(m--){            scanf("%d%d",&a,&b);            int tempq=queryMax(a,b,1,n,1);            int tempp=queryMin(a,b,1,n,1);            //cout<<tempq<<" "<<tempp<<endl;            printf("%d\n",abs(tempp-tempq));        }    }    return 0;}

A Simple Problem with Integers

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn=100005;long long sum[maxn<<2];long long col[maxn<<2];void pushup(int rt){    sum[rt]=sum[rt<<1]+sum[rt<<1|1];}void pushdown(int rt,int m){    if(col[rt]){        col[rt<<1]+=col[rt];        col[rt<<1|1]+=col[rt];        sum[rt<<1]+=(m-(m>>1))*col[rt];        sum[rt<<1|1]+=(m>>1)*col[rt];        col[rt]=0;    }}void build(int l,int r,int rt){    col[rt]=0;    if(l==r){        scanf("%lld",&sum[rt]);        return;    }    int m=(l+r)>>1;    build(lson);    build(rson);    pushup(rt);}void updata(long long L,long long R,long long c,int l,int r,int rt){    if(L<=l&&r<=R){        col[rt]+=c;        sum[rt]+=(r-l+1)*c;        return;    }    pushdown(rt,(r-l+1));    int m=(l+r)>>1;    if(L<=m) updata(L,R,c,lson);    if(R>m) updata(L,R,c,rson);    pushup(rt);}long long query(long long L,long long R,int l,int r,int rt){    if(L<=l&&r<=R){        return sum[rt];    }    pushdown(rt,(r-l+1));    long long res=0;    int m=(l+r)>>1;    if(L<=m) res+=query(L,R,lson);    if(R>m) res+=query(L,R,rson);    return res;}int main(){    int n,m;    long long a,b,c;    //freopen("1.txt","r",stdin);    while(~scanf("%d%d",&n,&m)){        memset(sum,0,sizeof(sum));        build(1,n,1);        char s[10];        while(m--){            scanf("%s",s);            if(s[0]=='Q'){                scanf("%lld%lld",&a,&b);                printf("%lld\n",query(a,b,1,n,1));            }            if(s[0]=='C'){                scanf("%lld%lld%lld",&a,&b,&c);                updata(a,b,c,1,n,1);            }        }    }    return 0;}

成段更新还要多理解一下。bug都是照着模版找的也是羞耻。还有几次都不写return然后程序就崩溃了。。。。自己还很懵。还有一个不太好的习惯就是定义变量都是想起来要用了才定义。然后自己都不知道它到底定义在什么地方了。就不好检查。以后还是统一写在一个地方比较好。那个long long 类型定义成int。找半天都找不出来。

既然已经写到这了。那就顺便总结一下周赛吧。这周赛也是相当羞耻。除了自己出的题目其他题都没怎么写。有一道其实不难的题目,我信心满满地在五分钟内交了三次之后还是WA。就不想做题了。颓了四个小时。那一天情绪都很崩溃。其实这几场比赛下来我应该要意识到心态是很重要的事情,努力调整好自己的情绪吧。如果这都控制不好的话,控制比赛的时候的节奏就跟难了。

原创粉丝点击