【HDU 5828】Rikka with Sequence(线段树)

来源:互联网 发布:mysql my.ini配置 编辑:程序博客网 时间:2024/06/08 06:32

【HDU 5828】Rikka with Sequence(线段树)

Rikka with Sequence

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2311    Accepted Submission(s): 391


Problem Description
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

Yuta has an array A with n numbers. Then he makes m operations on it.

There are three type of operations:

1 l r x : For each i in [l,r], change A[i] to A[i]+x
2 l r : For each i in [l,r], change A[i] to A[i]
3 l r : Yuta wants Rikka to sum up A[i] for all i in [l,r]

It is too difficult for Rikka. Can you help her?
 

Input
The first line contains a number t(1<=t<=100), the number of the testcases. And there are no more than 5 testcases with n>1000.

For each testcase, the first line contains two numbers n,m(1<=n,m<=100000). The second line contains n numbers A[1]~A[n]. Then m lines follow, each line describe an operation.

It is guaranteed that 1<=A[i],x<=100000.
 

Output
For each operation of type 3, print a lines contains one number – the answer of the query.
 

Sample Input
1
5 5
1 2 3 4 5
1 3 5 2
2 1 4
3 2 4
2 3 5
3 1 5
 

Sample Output
5
6
 

Author
学军中学
 

Source
2016 Multi-University Training Contest 8
 

题目大意:
区间三种操作。
1 区间加
2 区间开根
3 区间求和

第一个和第三个用Lazy外加合并相同区间。时间很充裕
开根和区间加不一样的是与元素本身有关。所以很爆炸的要找到每一个叶子。
如果单单这样其实最差的复杂度只会在构造出这种序列后的第一次开根。
但是有一种特殊情况,类似(2,3)+6(8,9)sqrt(2,3)
这样如果序列是交错排列的2 3 2 3 2 3 2 3,然后对区间不断+6 开根 +6 开根,就退化到了单次O(n)

这组数据是在赛后加的,当时一片片TLE……现在一瞅过了不少,然后百度了一下发现有人发了更优美的题解,然后就来补了一下。

开根的处理就是除了维护区间和外,再维护一个区间最大mx与最小mn。
当区间mx-mn <= 1 && sqrt(mx)-sqrt(mn) <= 1,就可以cut了,因为开根前后差值是一样的,就变为了区间减法,lazy标记一下就可以了

另发现绝版输入挂,常数优化绝妙

代码如下:

#include <iostream>#include <cmath>#include <vector>#include <cstdlib>#include <cstdio>#include <climits>#include <ctime>#include <cstring>#include <queue>#include <stack>#include <list>#include <algorithm>#include <map>#include <set>#define LL long long#define Pr pair<int,int>#define frd(ch) freopen(ch,"r",stdin)#define fwrite(ch) freopen(ch,"w",stdout)using namespace std;const int INF = 0x3f3f3f3f;const int msz = 112345;const int mod = 1e9+7;const double eps = 1e-8;const int BufferSize=1<<16;char buffer[BufferSize],*head,*tail;inline char Getchar() {    if(head==tail) {        int l=fread(buffer,1,BufferSize,stdin);        tail=(head=buffer)+l;    }    return *head++;}inline int read() {    int x=0,f=1;char c=Getchar();    for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;    for(;isdigit(c);c=Getchar()) x=x*10+c-'0';    return x*f;}LL sum[4*msz],mx[4*msz],mn[4*msz],lz[4*msz];void down(int root,int l,int r){    if(!lz[root]) return;    int mid = (l+r)>>1;    mx[root<<1] += lz[root];    mx[root<<1|1] += lz[root];    mn[root<<1] += lz[root];    mn[root<<1|1] += lz[root];    sum[root<<1] += lz[root]*(mid-l+1);    sum[root<<1|1] += lz[root]*(r-mid);    lz[root<<1] += lz[root];    lz[root<<1|1] += lz[root];    lz[root] = 0;}void up(int root){    sum[root] = sum[root<<1]+sum[root<<1|1];    mx[root] = max(mx[root<<1],mx[root<<1|1]);    mn[root] = min(mn[root<<1],mn[root<<1|1]);}void Add(int root,int l,int r,int ll,int rr,LL ad){    if(l == ll && r == rr)    {        lz[root] += ad;        sum[root] += ad*(r-l+1);        mx[root] += ad;        mn[root] += ad;        return;    }    int mid = (l+r)>>1;    down(root,l,r);    if(mid >= rr) Add(root<<1,l,mid,ll,rr,ad);    else if(mid+1 <= ll) Add(root<<1|1,mid+1,r,ll,rr,ad);    else    {        Add(root<<1,l,mid,ll,mid,ad);        Add(root<<1|1,mid+1,r,mid+1,rr,ad);    }    up(root);}LL Sum(int root,int l,int r,int ll,int rr){    if(l == ll && r == rr)    {        return sum[root];    }    int mid = (l+r)>>1;    down(root,l,r);    if(mid >= rr) return Sum(root<<1,l,mid,ll,rr);    else if(mid+1 <= ll) return Sum(root<<1|1,mid+1,r,ll,rr);    return Sum(root<<1,l,mid,ll,mid)+Sum(root<<1|1,mid+1,r,mid+1,rr);}void Sqrt(int root,int l,int r,int ll,int rr){    //printf("[%d,%d] mx%lld mn%lld\n",l,r,mx[root],mn[root]);    if(l == ll && r == rr)    {        LL cut;        if(mx[root] == mn[root])        {            cut = mx[root]-floor(sqrt(mx[root]*1.0));            lz[root] -= cut;            sum[root] -= cut*(r-l+1);            mx[root] = mn[root] = mx[root]-cut;            return;        }        else if(mx[root]-mn[root] == 1)        {            LL t1,t2;            t1 = floor(sqrt(mx[root]*1.0));            t2 = floor(sqrt(mn[root]*1.0));            if(t1-t2 == 1)            {                cut = mx[root]-t1;                lz[root] -= cut;                sum[root] -= cut*(r-l+1);                mx[root] = t1;                mn[root] = t2;                return;            }        }    }    int mid = (l+r)>>1;    down(root,l,r);    if(mid >= rr) Sqrt(root<<1,l,mid,ll,rr);    else if(mid+1 <= ll) Sqrt(root<<1|1,mid+1,r,ll,rr);    else    {        Sqrt(root<<1,l,mid,ll,mid);        Sqrt(root<<1|1,mid+1,r,mid+1,rr);    }    up(root);}void init(int root,int l,int r){    lz[root] = 0;    if(l == r)    {        sum[root] = read();        mx[root] = mn[root] = sum[root];        return;    }    int mid = (l+r)>>1;    init(root<<1,l,mid);    init(root<<1|1,mid+1,r);    up(root);}int main(){    //frd("1008.in");    //fwrite("m.out");    int t,opt,l,r,x,n,q;    t = read();    while(t--)    {        n = read();        q = read();        init(1,1,n);        while(q--)        {            opt = read();            l = read();            r = read();            if(opt == 1)            {                x = read();                Add(1,1,n,l,r,x);            }            else if(opt == 2)            {                Sqrt(1,1,n,l,r);            }            else printf("%lld\n",Sum(1,1,n,l,r));        }    }    return 0;}
0 0
原创粉丝点击