HDU 5828 Rikka with Sequence 线段树优化

转:
http://blog.csdn.net/xzxxzx401/article/details/52196950
题意

很明确是线段树,需要三种操作:区间更新(加值),区间开根号,区间求和。区间开根号就是区间内部每一个值开根号。

思路

先膜吧:我和这个大佬的代码风格很像,所以看的很舒服,大佬思路也很详细清晰,适合我这种咸鱼看。膜膜膜。

区间更新和求和直接套线段树板子,问题就在于区间开跟。开跟没有什么特别好的性质,首先想到的是朴素O(n)开跟,必T。开始优化。

额外再保存区间内部最大值与最小值。如果最大值是1,那么直接return,1开跟没卵用。这个优化比较有用,因为100000开4~5次跟就是1了,一个数老被开跟。。。啥也不剩了。

保存了区间最大最小值,那么如果区间最大值等于最小值,说明区间内所有值是一样的。那么可以变成区间加法操作。lazy+=(sqrt(data[rt])-data[rt])。

接下来的优化就很神奇了。。大佬说:

在昨天数据加强了以后,看到ACFun群里糖老师随手出了个数据卡掉了大部分人的程序,就是我之前的那个。
比如说:2 3 2 3 2 3这样10万个数字。然后10万次操作,(整体+6,整体sqrt)。
这个数据,我之前的程序要跑好几分钟,因为每个相邻的数字都不一样,而且整体加了以后,开方以后还是保持这样的情况,也就是说,每次操作以后,不能找到整段相等的情况。这样的话,就会一直更新下去,就非常慢。
这种情况只可能出现在max-min==1的情况。这样的区间开跟结果有两种,要么开跟后区间最大值最小值相等了。这样的需要加一个类似lazy的标记cover,优先级比lazy高。因为这个标记可以存区间值到底应该是多少,如果pushdown时这个值不是0,直接更新节点。另一个结果是开跟后区间极差仍然是1。这样相当于区间全减去一个值。用区间加做就可以了。

至于大佬说的输入挂,我在HDU上交了不带挂的,也过了。所以不知道怎么回事。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <iomanip>
#include <string>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;
const int MAXN=100005;
typedef long long int LL;

template <class T>
inline void rd(T &x){
    char c=getchar(); x=0;while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
struct Tree{
    LL data=0;
    LL lazy=0;
    LL ma=0;
    LL mi=0;
    LL manum=0;
    LL minum=0;
    LL cover=0;
}sum[MAXN<<2];//线段树

inline void PushUp(int rt)
{
    sum[rt].data=sum[rt<<1].data+sum[rt<<1|1].data;
    sum[rt].ma=max(sum[rt<<1].ma,sum[rt<<1|1].ma);
    sum[rt].mi=min(sum[rt<<1].mi,sum[rt<<1|1].mi);
    sum[rt].manum=sum[rt].minum=0;
    if(sum[rt].ma==sum[rt<<1].ma) sum[rt].manum+=sum[rt<<1].manum;
    if(sum[rt].ma==sum[rt<<1|1].ma) sum[rt].manum+=sum[rt<<1|1].manum;
    if(sum[rt].mi==sum[rt<<1].mi) sum[rt].minum+=sum[rt<<1].minum;
    if(sum[rt].mi==sum[rt<<1|1].mi) sum[rt].minum+=sum[rt<<1|1].minum;
}
inline void PushDown(int rt,int m)
{
    if(sum[rt].cover!=0){
        sum[rt<<1].cover=sum[rt<<1|1].cover=sum[rt].cover;
        sum[rt<<1].data=(LL) sum[rt].cover*(m-(m>>1));
        sum[rt<<1|1].data=(LL) sum[rt].cover*(m>>1);
        sum[rt<<1].ma=sum[rt<<1|1].ma=sum[rt<<1].mi=sum[rt<<1|1].mi=sum[rt].cover;
        sum[rt<<1].manum=sum[rt<<1].minum=(m-(m>>1));
        sum[rt<<1|1].manum=sum[rt<<1|1].minum=(m>>1);
        sum[rt<<1].lazy=sum[rt<<1|1].lazy=0;
        sum[rt].cover=0;
    }
    if(sum[rt].lazy!=0)
    {
        sum[rt<<1].lazy+=sum[rt].lazy;
        sum[rt<<1|1].lazy+=sum[rt].lazy;
        sum[rt<<1].data+=(sum[rt].lazy)*(m-(m>>1));
        sum[rt<<1|1].data+=(sum[rt].lazy)*(m>>1);
        sum[rt<<1].ma+=sum[rt].lazy;
        sum[rt<<1].mi+=sum[rt].lazy;
        sum[rt<<1|1].ma+=sum[rt].lazy;
        sum[rt<<1|1].mi+=sum[rt].lazy;
        sum[rt].lazy=0;
    }
}
inline void build(int l,int r,int rt) 
{
    sum[rt].lazy=sum[rt].manum=sum[rt].minum=sum[rt].cover=0;
    if(l==r)
    {
        scanf("%lld",&(sum[rt].data));
        //rd(sum[rt].data);
        sum[rt].ma=sum[rt].data;
        sum[rt].mi=sum[rt].data;
        sum[rt].manum=sum[rt].minum=1;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}

inline void update(int L,int R,int c,int l,int r,int rt) 
{
    if(L<=l && r<=R)
    {
        sum[rt].lazy+=c;
        sum[rt].data+=(LL)c*(r-l+1);
        sum[rt].ma+=c;
        sum[rt].mi+=c;
        return;
    }
    PushDown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m) update(L,R,c,lson);
    if(m<R) update(L,R,c,rson);
    PushUp(rt);
}
inline void update_s(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        if(sum[rt].ma==1) return;
        if(l==r)
        {
            sum[rt].data=floor(sqrt(sum[rt].data));
            sum[rt].ma=sum[rt].data;
            sum[rt].mi=sum[rt].data;
            return;
        }
        if(sum[rt].ma==sum[rt].mi)
        {
            LL temp=sum[rt].ma;
            sum[rt].ma=floor(sqrt(temp));
            sum[rt].mi=floor(sqrt(temp));
            sum[rt].data=(LL)sum[rt].ma*(r-l+1);
            sum[rt].lazy+=(sum[rt].ma-temp);
            return;
        }
        else if(sum[rt].ma-sum[rt].mi==1)
        {
            LL temp=sum[rt].ma;
            sum[rt].ma=floor(sqrt(sum[rt].ma));
            sum[rt].mi=floor(sqrt(sum[rt].mi));
            if(sum[rt].ma-sum[rt].mi==1)
            {
                sum[rt].lazy+=(sum[rt].ma-temp);
                sum[rt].data=(LL) sum[rt].ma*sum[rt].manum+(LL) sum[rt].mi*sum[rt].minum;

            }
            else
            {
                sum[rt].manum=sum[rt].minum=r-l+1;
                sum[rt].cover=sum[rt].ma;
                sum[rt].lazy=0;
                sum[rt].data=(LL) sum[rt].ma*(r-l+1);
            }
            return;
        }
        PushDown(rt,r-l+1);
        int m=(l+r)>>1;
        update_s(L,R,lson);
        update_s(L,R,rson);
        PushUp(rt);
        return;
    }

    PushDown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m) update_s(L,R,lson);
    if(m<R) update_s(L,R,rson);
    PushUp(rt);
}

inline LL query(int L,int R,int l,int r,int rt) {
    if(L<=l && r<=R) 
    {
        return sum[rt].data;
    }
    PushDown(rt,r-l+1);
    int m=(l+r)>>1;
    LL ret=0;
    if(L<=m) ret+=query(L,R,lson);
    if(m<R) ret+=query(L,R,rson);
    return ret;
}
int main() 
{
    //freopen("1008.in","r",stdin);
    //freopen("out.out","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int m,n;
        scanf("%d%d",&n,&m);
        build(1,n,1);
        int s,l,r;
        while(m--)
        {
            scanf("%d%d%d",&s,&l,&r);
            if(s==1)
            {
                int x;
                scanf("%d",&x);
                update(l,r,x,1,n,1);
            }
            else if(s==2)
            {
                update_s(l,r,1,n,1);

            }
            else
            {
                LL res=query(l,r,1,n,1);
                printf("%lld\n",res);
            }
        }
    }
    return 0;
}
posted @ 2017-09-19 21:17  黑码的博客  阅读(85)  评论(0编辑  收藏  举报