线段树UVa11992

要建多个线段树,有两个基本操作,set和add,优先级上,set比add高,注意关系;

query里还是要用到pushdown,有pushdown的地方就一定要有maintain,两者有依存关系;

但是pushdown之后,在哪里,在什么位置maintain,不太明白;

写完了,好多错误,,maintain对于子节点和中间节点是有区别的,,query是需要pushdown的;

即便如此还是不可逆转的TLE,超时,结果发现inline很管用啊,一下就到3s多了,过了;

其实超时的原因是p,2*p,2*p+1,应该写成p<<1,p<<1|1,毕竟计算机的位运算比乘法快得多,这样改也可以过;

看到一位同学直接写成了一维数组,就是类似于把二维写成一维,只要1s多一点,没整明白快在哪里。

写出来还是很不容易的。。调试花了差不多2个小时。

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstdio>

using namespace std;
#define RR 22
#define C 3000005
#define INF 1000000000

struct node {
    int L,R;
    int Sum,Min,Max;
    int Set,Add;
    node(int sum=0,int c_min=INF,int c_max=0):Sum(sum),Min(c_min),Max(c_max)
    {}
};

node st[RR][C];
int main_r, c, m, opr, x1, x2, y1, y2, v;;

 void ST_init(int p,int l,int r)
{
    for (int row=1;row<=main_r;row++) {
        st[row][p].L=l; st[row][p].R=r;
        st[row][p].Sum= st[row][p].Max= st[row][p].Min = 0;
        st[row][p].Add=0; st[row][p].Set=-1;
    }
    if (l<r) {
        int mid=(l+r)>>1;
        ST_init(p<<1,l,mid);
        ST_init(p<<1|1,mid+1,r);
    }
}

inline void pushdown(int p,int row)
{
    if (st[row][p].Set>=0) {
        st[row][p<<1].Set = st[row][p<<1|1].Set = st[row][p].Set;
        st[row][p<<1].Add = st[row][p<<1|1].Add = st[row][p].Add;
    }
    else if (st[row][p].Add>0){
            st[row][p<<1].Add +=st[row][p].Add;
            st[row][p<<1|1].Add +=st[row][p].Add;
        }

    st[row][p].Set=-1;
    st[row][p].Add=0;
}

inline void maintain(int p,int row)
{
    if (st[row][p].Set>=0) {
        st[row][p].Sum = (st[row][p].R-st[row][p].L+1)*(st[row][p].Set+st[row][p].Add);
        st[row][p].Max = st[row][p].Set+st[row][p].Add;
        st[row][p].Min = st[row][p].Set+st[row][p].Add;
    }
    else {
        if (st[row][p].L<st[row][p].R) {
            st[row][p].Sum = st[row][p<<1].Sum + st[row][p<<1|1].Sum;
            st[row][p].Max = max(st[row][p<<1].Max,st[row][p<<1|1].Max);
            st[row][p].Min = min(st[row][p<<1].Min,st[row][p<<1|1].Min);
        }
        else {
            st[row][p].Sum = st[row][p].Max = st[row][p].Min = 0;
        }
        st[row][p].Sum += st[row][p].Add*(st[row][p].R-st[row][p].L+1);
        st[row][p].Max += st[row][p].Add;
        st[row][p].Min += st[row][p].Add;
    }
}

void update(int p,int l,int r,int v,int opr,int row)
{
    if (st[row][p].L>=l && st[row][p].R<=r) {
        if (opr==1) {
            st[row][p].Add+=v;
        }
        else {
            st[row][p].Set=v;
            st[row][p].Add=0;
        }
    }
    else {
        pushdown(p,row);
        int mid=(st[row][p].L+st[row][p].R)/2;
        if (l<=mid) update(p<<1,l,r,v,opr,row);
        else maintain(p<<1,row);
        if (r>mid) update(p<<1|1,l,r,v,opr,row);
        else maintain(p<<1|1,row);
    }
    maintain(p,row);
}

node query(int p,int l,int r,int row)
{
    if (st[row][p].Set>=0) {
        return node((st[row][p].Set+st[row][p].Add)*(min(st[row][p].R,r)-max(st[row][p].L,l)+1) ,
                    st[row][p].Set+st[row][p].Add,
                    st[row][p].Set+st[row][p].Add);
    }
    else if (st[row][p].L==l && st[row][p].R==r) {
        return st[row][p];
    }
    else {
        pushdown(p,row);
        maintain(p<<1,row);
        maintain(p<<1|1,row);
        maintain(p,row);
        int mid=(st[row][p].L+st[row][p].R)/2;
        node t1,t2;
        if (l<=mid)
            t1=query(p<<1,l,min(mid,r),row);
        if (r>mid)
            t2=query(p<<1|1,max(mid+1,l),r,row);

        return node(t1.Sum+t2.Sum,
                    min(t1.Min,t2.Min),
                    max(t1.Max,t2.Max));

    }

}

int main()
{
    freopen("1.in","r",stdin);

    while (scanf("%d%d%d",&main_r,&c,&m)!=EOF) {
            ST_init(1,1,c);

        while (m--) {
            scanf("%d%d%d%d%d",&opr,&x1,&y1,&x2,&y2);
            if (opr<3) {
                scanf("%d",&v);
                for (int row=x1;row<=x2;row++)
                    update(1,y1,y2,v,opr,row);
            }
            else {
                node ans;
                for (int row=x1;row<=x2;row++) {
                    node tmp=query(1,y1,y2,row);
                    ans.Sum += tmp.Sum;
                    ans.Max = max(ans.Max,tmp.Max);
                    ans.Min = min(ans.Min,tmp.Min);
                }
                printf("%d %d %d\n",ans.Sum,ans.Min,ans.Max);
            }
        }
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值