1. 程式人生 > >hdu 5828 Rikka with Sequence 【線段樹+優化】

hdu 5828 Rikka with Sequence 【線段樹+優化】

題意:給你n個數,q個操作,操作k,l,r,k=1時 區間[l,r]每個數加x,k=2時,區間[l,r]每個數開平方,k=3時,求區間[l,r]的和。

分析:我們知道一個數多次開平方會變成1,但是這裡的1操作會使這個數的值增大,所以直接判斷一個區間是否為1肯定超時。

官方題解加了個優化,就是判斷一個區間內是否為一個值,因為有些區間在操作1和2下會變成一個值。

但是有一組資料把標程hack了:10萬個2,3,2,3,2,3.......,10萬個操作 加6,開根。

這樣每個數相等的區間大小就為1了,標程T了。

我們來考慮這種資料,如果一個區間的極差>1,那麼經過多次1,2操作後,最終這個區間的極差要麼是0,要麼是1,那麼我們只要維護極差<=1的區間就好了。

後來也T了很久。。。要用讀入優化和輸入加到build裡,G++提交。

程式碼:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 100010
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CLRS(a,b,Size) memset((a),(b),sizeof((a[0]))*(Size+1))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int read() {
    char c=getchar();
    int re=0,f=1;
    while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') {re=re*10+c-'0';c=getchar();}
    return re*f;
}
int a[Mn];
ll sum[Mn*4];
ll maxx[Mn*4],minn[Mn*4];
ll maxNum[Mn*4],minNum[Mn*4];
ll all[Mn*4];
ll lazy[Mn*4];
void pushUp(int u) {
    sum[u]=sum[ul]+sum[ur];
    maxx[u]=max(maxx[ul],maxx[ur]);
    minn[u]=min(minn[ul],minn[ur]);
    maxNum[u]=minNum[u]=0;
    if(maxx[u]==maxx[ul]) maxNum[u]+=maxNum[ul];
    if(maxx[u]==maxx[ur]) maxNum[u]+=maxNum[ur];
    if(minn[u]==minn[ul]) minNum[u]+=minNum[ul];
    if(minn[u]==minn[ur]) minNum[u]+=minNum[ur];
}
void pushDown(int u,int l,int r) {
    if(all[u]) {
        int mid=(l+r)>>1;
        all[ul]=all[ur]=all[u];
        sum[ul]=all[u]*(mid-l+1);
        sum[ur]=all[u]*(r-mid);
        maxx[ul]=maxx[ur]=minn[ul]=minn[ur]=all[u];
        maxNum[ul]=minNum[ul]=mid-l+1;
        maxNum[ur]=minNum[ur]=r-mid;
        lazy[ul]=lazy[ur]=0;
        all[u]=0;
    }
    if(lazy[u]) {
        int mid=(l+r)>>1;
        lazy[ul]+=lazy[u];lazy[ur]+=lazy[u];
        sum[ul]+=lazy[u]*(mid-l+1);
        sum[ur]+=lazy[u]*(r-mid);
        maxx[ul]+=lazy[u];minn[ul]+=lazy[u];
        maxx[ur]+=lazy[u];minn[ur]+=lazy[u];
        lazy[u]=0;
    }
}
void build(int l,int r,int u) {
    all[u]=lazy[u]=maxx[u]=minn[u]=sum[u]=0;
    if(l==r) {
        maxx[u]=minn[u]=sum[u]=read();
        maxNum[u]=minNum[u]=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,ul);
    build(mid+1,r,ur);
    pushUp(u);
}
int s,t;
void add(int l,int r,int u,int x) {
    if(s<=l&&t>=r) {
        sum[u]+=(ll)x*(r-l+1);
        minn[u]+=x;
        maxx[u]+=x;
        lazy[u]+=x;
        return ;
    }
    pushDown(u,l,r);
    int mid=(l+r)>>1;
    if(s<=mid) add(l,mid,ul,x);
    if(t>mid) add(mid+1,r,ur,x);
    pushUp(u);
}
void Sqrt(int l,int r,int u) {
    if(s<=l&&t>=r&&(maxx[u]-minn[u]<=1)) {
        if(maxx[u]==1) return ;
        int x=maxx[u];
        if(maxx[u]==minn[u]) {
            minn[u]=maxx[u]=floor(sqrt(x));
            lazy[u]+=maxx[u]-x;
            sum[u]=maxx[u]*(r-l+1);
            return ;
        } else if(maxx[u]-minn[u]==1){
            maxx[u]=floor(sqrt(maxx[u]));
            minn[u]=floor(sqrt(minn[u]));
            if(maxx[u]==minn[u]) {
                maxNum[u]=minNum[u]=r-l+1;
                lazy[u]=0;
                all[u]=maxx[u];
                sum[u]=maxx[u]*maxNum[u];
            } else if(maxx[u]-minn[u]==1) {
                lazy[u]+=maxx[u]-x;
                sum[u]=maxx[u]*maxNum[u]+minn[u]*minNum[u];
            }
            return ;
        }
        return ;
    }
    pushDown(u,l,r);
    int mid=(l+r)>>1;
    if(s<=mid) Sqrt(l,mid,ul);
    if(t>mid) Sqrt(mid+1,r,ur);
    pushUp(u);
}
ll query(int l,int r,int u) {
    if(s<=l&&t>=r) {
        return sum[u];
    }
    pushDown(u,l,r);
    int mid=(l+r)>>1;
    ll re=0;
    if(s<=mid) re+=query(l,mid,ul);
    if(t>mid) re+=query(mid+1,r,ur);
    return re;
}
int main() {
    int T=read(),k;
    while(T--) {
        int n=read(),m=read();
        build(1,n,1);
        while(m--) {
            k=read(),s=read(),t=read();
            if(k==1) {
                int x=read();
                add(1,n,1,x);
            } else if(k==2){
                Sqrt(1,n,1);
            } else {
                printf("%I64d\n",query(1,n,1));
            }
        }
    }
    return 0;
}


相關推薦

hdu 5828 Rikka with Sequence 線段+優化

題意:給你n個數,q個操作,操作k,l,r,k=1時 區間[l,r]每個數加x,k=2時,區間[l,r]每個數開平方,k=3時,求區間[l,r]的和。 分析:我們知道一個數多次開平方會變成1,但是這裡的1操作會使這個數的值增大,所以直接判斷一個區間是否為1肯定超時。 官方

HDU 5828Rikka with Sequence線段

Rikka with SequenceTime Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2311  

HDU 4893 多校聯合 Wow! Such Sequence!線段

題意在這裡就不說了。直接說思路,這是一道裸的線段樹,每個節點儲存區間的和sum以及區間變成斐波那契數的和fs。然後就是簡單點修改和區間修改的事了。 詳細見程式碼 #include <cstdio> #include <cstring> #inclu

HDU 1754 I Hate It 線段單點修改 區間查詢

update miss mem define 多少 pre otto 操作 show 題目傳送門:http://acm.hdu.edu.cn/showproblem.php?pid=1754 I Hate It Time Limit: 9000/3000 MS (Java/

HDU 1166 敵兵佈陣線段(單點更新與區間求和)

C國的死對頭A國這段時間正在進行軍事演習,所以C國間諜頭子Derek和他手下Tidy又開始忙乎了。A國在海岸線沿直線佈置了N個工兵營地,Derek和Tidy的任務就是要監視這些工兵營地的活動情況。由於採取了某種先進的監測手段,所以每個工兵營地的人數C國都掌握的一清二楚,每個工兵營地的人數都有可能發生

A Simple Problem with Integers 線段區間更新 區間查詢

POJ   3468 題意就不說了,之間看程式碼; 程式碼是對的,如果大佬覺得註釋有問題可以說,會仔細更改? #include<stdio.h> #include<string.h> #include<string> #include

438D The Child and Sequence線段

Time limit 4000 ms Memory limit 262144 kB At the children’s day, the child came to Picks’s house, and messed his house up. Picks wa

HDU 1166 —— Just a Hook 線段 區間修改

http://acm.hdu.edu.cn/showproblem.php?pid=1698 要求:   1. 區間修改   2. 最後整個區間求和 分析:   因為沒有多次查詢,而只有最後的一次整個區

hdu 1754 I Hate It 線段 應用型別二 單點更新 區間最值模板

題目連線:http://acm.hdu.edu.cn/showproblem.php?pid=1754 Problem Description 很多學校流行一種比較的習慣。老師們很喜歡詢問,從某某到某某當中,分數最高的是多少。 這讓很多學生很反感。 不管你喜不喜歡,

HDU 1166 敵兵佈陣 線段

C國的死對頭A國這段時間正在進行軍事演習,所以C國間諜頭子Derek和他手下Tidy又開始忙乎了。A國在海岸線沿直線佈置了N個工兵營地,Derek和Tidy的任務就是要監視這些工兵營地的活動情況。由於採取了某種先進的監測手段,所以每個工兵營地的人數C國都掌握的一清二楚,每個工兵營地的人數都有可能發生變動,可能

HDU 1698 Just a Hook線段—區間更新

In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic stic

線段優化DP HDU 3698 Let the light guide us

ans build tchar bit txt 。。 bre hellip har 這篇博客主要是發現了…… #define cmin(x,y) (x>y?x=y:0) 要比 void cmin(int &x,int y){i

bzoj 1645: [Usaco2007 Open]City Horizon 城市地平線線段+hash

ash 離散化 hash pan != 題目 getchar() cit names bzoj題面什麽鬼啊…… 題目大意:有一個初始值均為0的數列,n次操作,每次將數列(ai,bi-1)這個區間中的數與ci取max,問n次後元素和 離散化,然後建立線段樹,每次修改在區間上打

BZOJ5334 [TJOI2018] 數學計算 線段分治

amp IT bit 分治 continue lse col %d ++ 題目分析:   大概是考場上的簽到題。首先mod不是質數,所以不能求逆元。註意到有加入操作和刪除操作。一個很典型的想法就是線段樹分治。建立時間線段樹然後只更改有影響的節點,最後把所有標記下傳。時間復雜

HDU1698 Just a Hook 線段入門

uil 機器 連續 fin case using -- pre 上一個 原題:原題鏈接 題意:(機器翻譯的...) 讓我們將鉤子的連續金屬棒從1到N編號。對於每次操作,Pudge可以將連續的金屬棒(從X到Y編號)改為銅棒,銀棒或金棒。 鉤的總值計算為N個金屬棒的值的總和。更

HDU1166敵兵布陣線段入門

sum char mes sca 敵兵布陣 bsp cas i++ 線段樹 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using n

SDOI2017點染色線段+LCT

get d+ i++ read 改變 rotate def 維護 n) 本來只是想練練LCT,沒想到是個線段樹 對於操作1:誒新的顏色?這不是access嗎? 也就是說,我們用一棵splay來表示一種顏色 操作2直接在LCT上亂搞…… 不對啊,操作3要查子樹 誒好像是靜態的

線段模板區間修改區間求和

蒟蒻線上段樹的路上繼續前進,lazy的出題人的奇思妙想——延遲標記震撼了他。。 線段樹模板題(二)——區間修改與查詢區間和:區間修改區間求和  【題目描述】   如題,已知一個數列,你需要進行下面兩種操作: 1.將某區間每一個數加上x 2.求出某區間每一個數的和

DP、線段優化琪露諾

跟去年(2017)PJ第四題幾乎是一樣的?/吐血 DP方程可以很簡單的推出來,f[i]=max{f[k]}+a[i] 然而這樣做是O(n^2)的 看一下資料,200000的話要不nlogn 要不n 由於題解裡面單調佇列和優先佇列都有人用了,那就來一發線段樹吧 (或者實情是:單調佇列不會打?) 只要維護i-r~