2016多校8 HDU 5828 Rikka with Sequence 线段树优化

来源:互联网 发布:锐速 原理 知乎 编辑:程序博客网 时间:2024/06/07 17:41

2016多校联合训练#8

HDU 5828 Rikka with Sequence

线段树优化,想法

传送门:HDU


题意

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


思路

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

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

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

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

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

    在昨天数据加强了以后,看到ACFun群里糖老师随手出了个数据卡掉了大部分人的程序,就是我之前的那个。
    比如说:2 3 2 3 2 3这样10万个数字。然后10万次操作,(整体+6,整体sqrt)。
    这个数据,我之前的程序要跑好几分钟,因为每个相邻的数字都不一样,而且整体加了以后,开方以后还是保持这样的情况,也就是说,每次操作以后,不能找到整段相等的情况。这样的话,就会一直更新下去,就非常慢。

  4. 这种情况只可能出现在max-min==1的情况。这样的区间开跟结果有两种,要么开跟后区间最大值最小值相等了。这样的需要加一个类似lazy的标记cover,优先级比lazy高。因为这个标记可以存区间值到底应该是多少,如果pushdown时这个值不是0,直接更新节点。另一个结果是开跟后区间极差仍然是1。这样相当于区间全减去一个值。用区间加做就可以了。

  5. 至于大佬说的输入挂,我在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|1using 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;}
0 0
原创粉丝点击