【WC2015模擬2.5】數組

Description

這裏寫圖片描述

Input

這裏寫圖片描述

Output

對於每個詢問操作,輸出滿足條件的子區間數

Sample Input

3
1 2 3
3
0
1 1 2
0

Sample Output

6
4

Solution

對於每個位置,考慮以這個位置開頭的子區間,最右能延伸到哪裏,設爲suf[i]。
爲了維護這個,設一個next[i]表示第i個位置之後的第一個同顏色的位置再哪裏
那麼suf[i]就是next[i]的後綴min
轉換成模型:對於給定序列,這個序列構成的單調棧的權值和(也可以是最大值,最小值等)
聽說這個模型是wc2013的樓房重建?
設find(i,j,p)表示在[i,j]區間後面加入一個p之後的單調棧的權值和
在這題中,單調棧是單調上升的
那麼對於區間的右半邊,求出最小值rmin
如果rmin<p ,那麼p對左半邊區間沒有影響,答案是find(i,mid,rmin)+find(mid+1,j,p)
否則,右邊被完全彈出,答案是find(i,mid,p)+p*(j-m)
如果i=j,直接考慮這個點是否會被p彈掉,輸出p或本身值
但是這樣會超時
設fm[i,j]表示將[i,j]區間的右邊最小值加入左邊的權值和,即find(i,mid,rmin)
這樣在find的時候直接調用這個,是O(1)的,查詢次數是log的
在每次修改時維護這個fm,也是會修改log次
最終複雜度是O(nlog2n)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define N 501000
#define INF 1010580540
#define ll long long
using namespace std;
int a[N],n,b[N],nxt[N];
ll t[N],g[N],fm[N];
set<int> c[N];
typedef set<int> :: iterator it;
ll find(ll v,ll x,ll y,ll p)
{
    if(x==y) return g[v]<=p?t[v]:p;
    ll m=(x+y)/2,rm=g[v*2+1];
    if(p<=rm) return find(v*2,x,m,p)+p*(y-m);
    return fm[v]+find(v*2+1,m+1,y,p);
}
void ins(int v,int i,int j,int x,int y)
{
    if(i==j)
    {
        t[v]=g[v]=y;
        return;
    }
    int m=(i+j)/2;
    if(x<=m) ins(v*2,i,m,x,y);
    else ins(v*2+1,m+1,j,x,y);
    t[v]=t[v*2]+t[v*2+1];
    g[v]=min(g[v*2],g[v*2+1]);
    fm[v]=find(v*2,i,m,g[v*2+1]);
}
int main()
{
    memset(g,60,sizeof(g));
    scanf("%d",&n);
    fo(i,1,n) scanf("%d",&a[i]),c[a[i]].insert(i),c[i].insert(n+1),c[i].insert(0),b[i]=n+1;
    fd(i,n,1) 
    ins(1,1,n,i,nxt[i]=b[a[i]]),b[a[i]]=i;
    int ac;scanf("%d",&ac);
    while(ac--)
    {
        int z;scanf("%d",&z);
        if(z==0)
        {
            ll ans=find(1,1,n,n+1);
            printf("%lld\n",ans-(ll)((ll)n*(ll)(n+1)/2));
        }
        else
        {
            int x,y;scanf("%d%d",&x,&y);
            int q=a[x];
            it pos=c[q].find(x);
            int z=*(--pos);
            nxt[z]=nxt[x];c[q].erase(x);
            if(z>0) ins(1,1,n,z,nxt[z]);
            a[x]=y;q=y;c[q].insert(x);
            pos=c[q].find(x);
            z=*(--pos);nxt[z]=x;
            if(z>0) ins(1,1,n,z,nxt[z]);
            pos++;
            z=*(++pos);nxt[x]=z;
            ins(1,1,n,x,z);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章