HDU 5828 多校第八场 1008 Rikka with Sequence(线段树--数据加强版)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5828

题意:三种操作,一种是区间增加,一种是区间开方,一种是区间求和。

原思路(数据已加强,这个方法已经过不了):很快能想到,如果一个100000的数字,最多开方个四五次以后,就变成1了,而且sqrt(1)=1,那么我们就可以在更新的时候想到一个很方便的剪枝,就是,如果这个区间的最大值是1,也就是这个区间全部是1的时候,就可以不继续递归下去了。

然后我就这么写了一发,结果TLE了。

但是还有一个思路可以剪枝。就是一段区间如果全部开根号到1以后,那么如果这段区间再增加值,整个区间的值就是一样的,当整个区间的值是一样的时候,只要开方一次,就能求出这个区间的值了。加了这个剪枝之后就AC了。

Update–补丁1.1(1900+ms AC):
这里写图片描述
被同学提醒了一下,在极差==1的时候,而且知道区间和,最大值和最小值的情况下,是可以直接计算出最大值和最小值的个数的,所以就可以不用在线段树里维护两个值了。就快得多了。

补丁1.0(2700+ms AC):
这里写图片描述

在昨天数据加强了以后,看到ACFun群里糖老师随手出了个数据卡掉了大部分人的程序,就是我之前的那个。
比如说:2 3 2 3 2 3这样10万个数字。然后10万次操作,(整体+6,整体sqrt)。
这个数据,我之前的程序要跑好几分钟,因为每个相邻的数字都不一样,而且整体加了以后,开方以后还是保持这样的情况,也就是说,每次操作以后,不能找到整段相等的情况。这样的话,就会一直更新下去,就非常慢。
但是我们可以思考一下,如果一个区间内的极差>1的时候,不断地进行整体加某个值然后开方,是没办法保持住这样的序列的(相邻两个极差都>1)。只有整个区间内的极差<=1的时候,才能起到这种效果。所以我们就在线段树上再增加一些信息。就是最大值和最小值,最大值的个数,最小值的个数。这样的话,如果区间内的极差==1的时候,我们也能直接对整段进行操作。就能处理前面的这种样例了。

然后在昨天的基础上考虑新情况,区间的极差==1的时候。那么这种情况开方以后有两种情况。1:整个区间相等了。2:整个区间的极差还是1。
对于第一种情况。我们只要加一个cover标记,加一个区间覆盖的标记就可以解决了。
对于第二种情况,相当于,区间减去了一个相等的值,修改一下区间增加的标记就可以了。然后在pushdown的时候增加一下cover的情况。

但是这样还是TLE,加了一个读入挂以后艰难的卡过去了。

//原思路:TLE
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define mp make_pair
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define calm (l+r)>>1
const int INF = 2139062143;

const int maxn=100010;
int n,m;
struct Seg{
    int mx[maxn<<2],mn[maxn<<2],tag[maxn<<2];
    ll sum[maxn<<2];
    inline void pushup(int rt){
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
        mn[rt]=min(mn[rt<<1],mn[rt<<1|1]);
    }
    inline void pushdown(int rt,int l,int r){
        if(tag[rt]!=0){
            int m=calm;
            ll llen=m-l+1;
            ll rlen=r-m;
            tag[rt<<1]+=tag[rt];tag[rt<<1|1]+=tag[rt];
            sum[rt<<1]+=tag[rt]*llen; sum[rt<<1|1]+=tag[rt]*rlen;
            mx[rt<<1]+=tag[rt];mx[rt<<1|1]+=tag[rt];
            mn[rt<<1]+=tag[rt];mn[rt<<1|1]+=tag[rt];
            tag[rt]=0;
        }
    }
    void print(int l,int r,int rt){
        if(l==r){
            printf("%I64d ",sum[rt]);
            return;
        }
        pushdown(rt,l,r);
        int m=calm;
        print(lson);print(rson);
    }
    void build(int l,int r,int rt){
        tag[rt]=0;
        if(l==r){
            scanf("%I64d",&sum[rt]);
            mx[rt]=mn[rt]=sum[rt];
            return;
        }
        int m=calm;
        build(lson);build(rson);
        pushup(rt);
    }
    void add(int L,int R,int v,int l,int r,int rt){
        if(L<=l&&r<=R){
            sum[rt]+=(ll)v*(r-l+1);
            mx[rt]+=v;
            mn[rt]+=v;
            tag[rt]+=v;
            return;
        }
        pushdown(rt,l,r);
        int m=calm;
        if(L<=m)add(L,R,v,lson);
        if(R>m)add(L,R,v,rson);
        pushup(rt);
    }
    void update(int L,int R,int l,int r,int rt){
        if(L<=l&&r<=R){
            if(mx[rt]==1)return;
            if(l==r){
                sum[rt]=floor(sqrt(sum[rt]));
                mx[rt]=mn[rt]=sum[rt];
                return;
            }
            if(mx[rt]==mn[rt]){
                int t=mx[rt];
                mx[rt]=mn[rt]=floor(sqrt(t));
                tag[rt]+=mx[rt]-t;
                sum[rt]=(ll)mx[rt]*(r-l+1);
                return;
            }
            pushdown(rt,l,r);
            int m=calm;
            update(L,R,lson);
            update(L,R,rson);
            pushup(rt);
            return;
        }
        pushdown(rt,l,r);
        int m=calm;
        if(L<=m)update(L,R,lson);
        if(R>m)update(L,R,rson);
        pushup(rt);
    }
    ll query(int L,int R,int l,int r,int rt){
        if(L<=l&&r<=R){
            return sum[rt];
        }
        pushdown(rt,l,r);
        int m=calm;
        ll ans=0;
        if(L<=m)ans+=query(L,R,lson);
        if(R>m)ans+=query(L,R,rson);
        return ans;
    }
}tree;
int main(){
    //freopen("D://input.txt","r",stdin);
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        tree.build(1,n,1);
        while(m--){
            int op,l,r;
            scanf("%d%d%d",&op,&l,&r);
            if(op==1){
                int x;scanf("%d",&x);
                tree.add(l,r,x,1,n,1);
            }
            else if(op==2){
                tree.update(l,r,1,n,1);
            }
            else{
                printf("%I64d\n",tree.query(l,r,1,n,1));
            }
            //tree.print(1,n,1);printf("\n");
        }
    }
    return 0;
}
//在区间内维护两种数:AC
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define mp make_pair
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define calm (l+r)>>1
const int INF = 2139062143;

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();  }
}

const int maxn=100010;
int n,m;
struct Seg{
    int mx[maxn<<2],mn[maxn<<2],tag[maxn<<2],cover[maxn<<2];
    ll sum[maxn<<2];
    inline void pushup(int rt){
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
        mn[rt]=min(mn[rt<<1],mn[rt<<1|1]);
    }
    inline void pushdown(int rt,int l,int r){
        if(cover[rt]!=0){
            int m=calm;
            ll llen=m-l+1;
            ll rlen=r-m;
            cover[rt<<1]=cover[rt<<1|1]=cover[rt];
            sum[rt<<1]=(ll)cover[rt]*llen; sum[rt<<1|1]=(ll)cover[rt]*rlen;
            mx[rt<<1]=mx[rt<<1|1]=mn[rt<<1]=mn[rt<<1|1]=cover[rt];
            tag[rt<<1]=tag[rt<<1|1]=0;
            cover[rt]=0;
        }
        if(tag[rt]!=0){
            int m=calm;
            ll llen=m-l+1;
            ll rlen=r-m;
            tag[rt<<1]+=tag[rt];tag[rt<<1|1]+=tag[rt];
            sum[rt<<1]+=tag[rt]*llen; sum[rt<<1|1]+=tag[rt]*rlen;
            mx[rt<<1]+=tag[rt];mx[rt<<1|1]+=tag[rt];
            mn[rt<<1]+=tag[rt];mn[rt<<1|1]+=tag[rt];
            tag[rt]=0;
        }
    }
    void print(int l,int r,int rt){
        if(l==r){
            printf("%I64d ",sum[rt]);
            return;
        }
        pushdown(rt,l,r);
        int m=calm;
        print(lson);print(rson);
    }
    void build(int l,int r,int rt){
        tag[rt]=cover[rt]=0;
        if(l==r){
            //scanf("%I64d",&sum[rt]);
            rd(sum[rt]);
            mx[rt]=mn[rt]=sum[rt];
            return;
        }
        int m=calm;
        build(lson);build(rson);
        pushup(rt);
    }
    void add(int L,int R,int v,int l,int r,int rt){
        if(L<=l&&r<=R){
            sum[rt]+=(ll)v*(r-l+1);
            mx[rt]+=v;
            mn[rt]+=v;
            tag[rt]+=v;
            return;
        }
        pushdown(rt,l,r);
        int m=calm;
        if(L<=m)add(L,R,v,lson);
        if(R>m)add(L,R,v,rson);
        pushup(rt);
    }
    void update(int L,int R,int l,int r,int rt){
        if(L<=l&&r<=R){
            if(mx[rt]==1)return;
            if(l==r){
                sum[rt]=floor(sqrt(sum[rt]));
                mx[rt]=mn[rt]=sum[rt];
                return;
            }
            if(mx[rt]==mn[rt]){
                int t=mx[rt];
                mx[rt]=mn[rt]=floor(sqrt(t));
                tag[rt]+=mx[rt]-t;
                sum[rt]=(ll)mx[rt]*(r-l+1);
                return;
            }
            else if(mx[rt]-mn[rt]==1){//区间极差==1的情况
                int ta=mx[rt],tb=mn[rt];
                int mxnum=sum[rt]-(ll)tb*(r-l+1);//直接计算出个数
                int mnnum=r-l+1-mxnum;
                mx[rt]=floor(sqrt(mx[rt]));
                mn[rt]=floor(sqrt(mn[rt]));
                if(mx[rt]-mn[rt]==1){
                    tag[rt]+=mx[rt]-ta;
                    sum[rt]=(ll)mx[rt]*mxnum+(ll)mn[rt]*mnnum;
                }
                else{

                    tag[rt]=0;cover[rt]=mx[rt];
                    sum[rt]=(ll)mx[rt]*(r-l+1);
                }
                return;
            }
            pushdown(rt,l,r);
            int m=calm;
            update(L,R,lson);
            update(L,R,rson);
            pushup(rt);
            return;
        }
        pushdown(rt,l,r);
        int m=calm;
        if(L<=m)update(L,R,lson);
        if(R>m)update(L,R,rson);
        pushup(rt);
    }
    ll query(int L,int R,int l,int r,int rt){
        if(L<=l&&r<=R){
            return sum[rt];
        }
        pushdown(rt,l,r);
        int m=calm;
        ll ans=0;
        if(L<=m)ans+=query(L,R,lson);
        if(R>m)ans+=query(L,R,rson);
        return ans;
    }
}tree;
int main(){
    //freopen("D://input.txt","r",stdin);
    int T;//scanf("%d",&T);
    rd(T);
    while(T--){
        //scanf("%d%d",&n,&m);
        rd(n);rd(m);
        tree.build(1,n,1);
        for(int i=1;i<=m;i++){
            int op,l,r;
            //scanf("%d%d%d",&op,&l,&r);
            rd(op);rd(l);rd(r);
            if(op==1){
                int x;//scanf("%d",&x);
                rd(x);
                tree.add(l,r,x,1,n,1);
            }
            else if(op==2){
                tree.update(l,r,1,n,1);
            }
            else{
                printf("%I64d\n",tree.query(l,r,1,n,1));
            }
            //tree.print(1,n,1);printf("\n");
        }
    }
    return 0;
}

你可能感兴趣的:(线段树)