洛谷P5069 [Ynoi2015]縱使日薄西山(樹狀數組,set)

洛谷題目傳送門c++

一血祭數組

向dllxl致敬!spa

算是YNOI中比較清新的吧,畢竟代碼只有1.25k。code

首先咱們對着題意模擬,尋找一些思路。ip

每次選了一個最大的數後,它和它周圍兩個數都要減一。這樣不管如何,咱們都選不到旁邊那兩個數,只有第一次選的那個數會對答案產生它的大小的貢獻。get

因而就能夠寫出一個\(O(nm\log n)\)的暴力用來對拍了it

#include<bits/stdc++.h>
#define LL long long
#define R register int
#define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
using namespace std;
const int SZ=1<<19,N=1e5+9;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int in(){
    G;while(*ip<'-')G;
    R x=*ip&15;G;
    while(*ip>'-'){x*=10;x+=*ip&15;G;}
    return x;
}
int a[N],b[N];
bool vis[N];
inline bool Cmp(R&x,R y){
    return a[x]>a[y]||(a[x]==a[y]&&x<y);
}
int main(){
    R n=in();
    for(R i=1;i<=n;++i)a[i]=in();
    for(R q=in();q--;){
        a[in()]=in();
        for(R i=1;i<=n;++i)b[i]=i;
        sort(b+1,b+n+1,Cmp);
        memset(vis+1,0,n);
        LL ans=0;
        for(R i=1;i<=n;++i){
            if(vis[b[i]])continue;
            vis[b[i]-1]=vis[b[i]]=vis[b[i]+1]=1;
            ans+=a[b[i]];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

進一步觀察,對於一個序列中的一個極長單調區間,咱們取到了最大的、第三大的、第五大的。。。class

考慮用set維護好序列的全部極值點,相鄰兩個極值點所包含區間的貢獻就能夠經過樹狀數組查區間和直接算(注意分奇偶)。統計

單點修改的時候,只會影響到本身周圍至多三個的極值點狀態、以及左右各至多兩個區間的單調性,暴力刪掉原來的貢獻再加新的貢獻就行了。數據

統計答案時細節不少,邊界問題也不少,想清楚後再動手仍是很舒服的。

時間複雜度\(O((n+m)\log n)\),由於數據範圍不怎麼卡(這一點也是YNOI極罕見的)因此蒟蒻直接犧牲常數來減小代碼長度了qaq

#include<bits/stdc++.h>
#define LL long long
#define I inline
#define R register int
#define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
using namespace std;
typedef set<int>::iterator IT;
const int SZ=1<<19,N=1e5+9;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int in(){
    G;while(*ip<'-')G;
    R x=*ip&15;G;
    while(*ip>'-'){x*=10;x+=*ip&15;G;}
    return x;
}
int n,a[N];LL ans;set<int>s;
struct BIT{
    LL a[N];
    I void Upd(R i,R v){
        for(;i<N;i+=i&-i)a[i]+=v;
    }
    I void Qry(R l,R r,LL v){
        for(R i=r;i;i-=i&-i)v+=a[i];
        for(R i=l;i;i-=i&-i)v-=a[i];
    }
}b[2];
#define ODD(O) ((*l^*O(j=l))&1)
I void Calc(IT l,IT r,R op){
    IT i,j;LL sum=*l&&a[*l+1]>a[*l]&&!ODD(--)&&!ODD(++)?a[*l]:0;
    for(i=l++;i!=r;i=l++)
        if(a[*l]>a[*i])b[*l&1].Qry(*i,*l,sum);
        else b[*i&1].Qry(*i,*l-ODD(++),sum);
    ans+=sum*op;
}
I void Chk(R x){
    if((a[x]>a[x-1])!=(a[x+1]>a[x]))s.insert(x);
    else s.erase(x);
}
I void Upd(R x){
    R y=in();
    IT i=s.lower_bound(x),l=i,r=i;
    --l;if(l!=s.begin())--l;
    ++r;if(r==s.end()||(*i==x&&++r==s.end()))--r;
    Calc(l,r,-1);
    b[x&1].Upd(x,y-a[x]);a[x]=y;
    Chk(x);if(x>1)Chk(x-1);if(x<n)Chk(x+1);
    Calc(l,r,1);
}
int main(){
    n=in();s.insert(0);s.insert(n+1);
    for(R i=1;i<=n;++i)Upd(i);
    for(R q=in();q;--q)Upd(in()),printf("%lld\n",ans);
    return 0;
}
相關文章
相關標籤/搜索