【upc】生命曲線(線段樹) —— 一個能讓你搞懂線段樹懶標的題目

下午3個半小時的成果


題目描述

 

Mr.L最近得了妄想症,他對自己生命的歷史和未來產生了一些幻覺。
他的眼前浮現出了自己的生命價值曲線。這條生命線不斷地變化,使他不斷懷疑着自己存在的意義……
Mr.L的生命價值曲線可以被簡化爲一個代表着Mr.L的每個階段的生命價值的序列。其中第i個階段的生命價值爲vi。
當他預感自己成功或失敗時,他的生命線上會遞增或遞減地增加或減少一些價值。他認爲這些價值的變化量是形成等差數列的。
還有時候,他預感到自己的大起大落,此時他一段時間的生命價值會發生反轉。
具體來說,若[l,r]時間內的生命價值發生了反轉,則其中的每個價值都會變成 它原先價值的相反數。
他對自己在某段時間內的生命價值很感興趣,所以還想求出某些時間段內的生命價值總和。

 

題目思路:

毫無疑問的說,這題明白的話,線段樹的懶標就差不多了。

這個題目要求三種操作:

1. 對區間[l,r]求和

2.對區間[l,r] 加一個 首項爲K 公差爲D 的等差數列

3.對區間[l,r]進行翻轉 a_i=-a_i

首先要解決這個問題的子問題 —— 區間維護等差數列,區間查詢。

考慮 等差數列的兩個屬性 首項a & 公差 d

假設在k節點下,增加了一個首項爲a 公差爲d 的等差數列,向下傳送時 :

相當於在左節點增加一個 首項爲a 公差爲d 的等差數列

相當於在右節點增加一個 首項爲 a+左節點的項數*d 公差爲d 的等差數列

所以維護兩個 類似懶標 的屬性 a & d

另外維護一個答案權值 w.

假設在k節點下  增加首項爲a,公差爲d 的等差數列, 那麼k節點下的權值和 也就對應增加 (2*a+(len-1)*d)*len/2 —— 等差數列求和公式

並且維護的懶標具有可相加性,所以a & d 的傳播 直接向下傳即可。

所以說根據 維護 a&d 就可以維護到每一個節點的權值。

那麼問題來了:

第三種操作,如何實現?

反轉我們可以將其考慮爲  * -1

所以這個題目轉換爲了,有兩種操作 ,第一種操作將[l,r]權值和+w, 第二種操作將[l,r]內權值和 *-1

這就涉及到 區間加法 與 區間乘法 在一起修改時 懶惰標記的優先級

考慮到乘法的優先級比加法的大,所以維護將區間乘法轉區間加法:

假設當前先進行加法: (x+y)*c  ->  x*c + y*c 也就是說先加後×的話,加法懶惰標記需要成*c。

假設當前先進行乘法:x*c+d  也就是說此時加法標記不需要任何改變

所以 down函數的寫法

void down(int k){
    t[k<<1].w=(t[k].mu*t[k<<1].w+t[k].add*(t[k<<1].r-t[k<<1].l+1))%mod;
    t[k<<1|1].w=(t[k].mu*t[k<<1|1].w+t[k].add*(t[k<<1|1].r-t[k<<1|1].l+1))%mod;
    t[k<<1].add=((t[k<<1].add*t[k].mu)+t[k].add)%mod;
    t[k<<1|1].add=((t[k<<1|1].add*t[k].mu)+t[k].add)%mod;
    t[k<<1].mu=(t[k<<1].mu*t[k].mu)%mod;
    t[k<<1|1].mu=(t[k<<1|1].mu*t[k].mu)%mod;
    t[k].mu=1;t[k].add=0;
}

不過這個題,是區間總體加一個數,所以後面不需要×區間長度了

所以這題就轉換爲 區間加法與區間乘法

區間加法加的值 通過 a,d去維護

區間乘法通過乘法懶標去維護

感覺這題...有點麻煩

具體的還是要細細看一下代碼:

Code(你品,你細品):

/*** keep hungry and calm CoolGuang!***/
//#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pp;
const ll INF=1e17;
const int maxn=2e6+6;
const int mod=20020421;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
struct node{
    int l,r;
    ll w;
    ll a,d;
    int f;
}t[maxn];
void push(int k){
    t[k].w=t[k<<1].w+t[k<<1|1].w;
}
void build(int k,int l,int r){
    t[k].l=l;t[k].r=r;
    t[k].a=t[k].d=0;
    t[k].f=1;
    if(l==r){
        read(t[k].w);
        return ;
    }
    int mid=(t[k].l+t[k].r)/2;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    push(k);
}
void down(int k){

    t[k<<1].a=t[k<<1].a*t[k].f+t[k].a;
    t[k<<1|1].a=t[k<<1|1].a*t[k].f+(t[k].a+(t[k<<1|1].l-t[k<<1].l)*t[k].d);
    t[k<<1].d=t[k<<1].d*t[k].f+t[k].d;
    t[k<<1|1].d=t[k<<1|1].d*t[k].f+t[k].d;
    t[k<<1].f*=t[k].f;
    t[k<<1|1].f*=t[k].f;
    t[k<<1].w=t[k<<1].w*t[k].f+((2*t[k].a+(t[k<<1].r-t[k<<1].l)*t[k].d)*(t[k<<1].r-t[k<<1].l+1))/2;
    t[k<<1|1].w=t[k<<1|1].w*t[k].f+((2*(t[k].a+(t[k<<1|1].l-t[k<<1].l)*t[k].d)+(t[k<<1|1].r-t[k<<1|1].l)*t[k].d)*(t[k<<1|1].r-t[k<<1|1].l+1))/2;
    t[k].a=t[k].d=0;
    t[k].f=1;
}
///ok
void update(int k,int x,int y,ll K,ll D){
    if(x<=t[k].l&&y>=t[k].r){
        t[k].a+=K+(t[k].l-x)*D;
        t[k].d+=D;
        t[k].w+=(2*(K+(t[k].l-x)*D)+(t[k].r-t[k].l)*D)*(t[k].r-t[k].l+1)/2;
        return;
    }
    down(k);
    int mid=(t[k].l+t[k].r)/2;
    if(x<=mid) update(k<<1,x,y,K,D);
    if(y>mid) update(k<<1|1,x,y,K,D);
    push(k);
}
///ok
void update_f(int k,int x,int y){
    if(x<=t[k].l&&y>=t[k].r){
        t[k].w*=-1;
        t[k].a*=-1;
        t[k].d*=-1;
        t[k].f*=-1;
        return;
    }
    down(k);
    int mid=(t[k].l+t[k].r)/2;
    if(x<=mid) update_f(k<<1,x,y);
    if(y>mid) update_f(k<<1|1,x,y);
    push(k);
}
///ok
ll query(int k,int x,int y){
    if(x<=t[k].l&&y>=t[k].r){
        return t[k].w;
    }
    down(k);
    int mid=(t[k].l+t[k].r)/2;
    ll ans=0;
    if(x<=mid) ans+=query(k<<1,x,y);
    if(y>mid) ans+=query(k<<1|1,x,y);
    push(k);
    return ans;
}
int main()
{
    read(n);read(m);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        int op,x,y;ll K,D;
        scanf("%d%d%d",&op,&x,&y);
        if(op==1){
            scanf("%lld%lld",&K,&D);
            update(1,x,y,K,D);
        }
        else if(op==2){
            printf("%lld\n",query(1,x,y));
        }
        else
            update_f(1,x,y);
    }
    return 0;
}
/***
w
***/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章