hdu-4747-Mex-线段树区域更新

来源:互联网 发布:公务员可以开淘宝店吗 编辑:程序博客网 时间:2024/05/21 06:42

部分题解摘抄cxlove,传送门:http://blog.csdn.net/acm_cxlove/article/details/11749383

题目:给出一个序列,mex{}表示集合中没有出现的最小的自然数。然后 求sigma(mex (i , j)).

做法:考虑左端点固定时的所有区间的mex值,这个序列是一个非递减了。。。首先要明白。

初始就是求出mex[i]表示 mex(1 , i),对于每一个左端点,就是一个区间求和。

现在需要考虑的是左端点的改变对于序列的影响。。。

即左端点从i -> i + 1,mex[j]的改变。。。。即删去ai对于序列的影响。

如果 a[j] = a[i] 且 j > i ,不存在a[k] = a[i]  j > k > i。即a[i]下一次出现的位置 。

根据mex的定义,我们知道 mex[k]不会改变, k >= j。因为删掉的ai还是存在于序列当中,所以不受影响。

之后需要考虑的是i +1 到 j - 1这段区间的mex值。。。删去了ai之后,使得原先mex值大于ai的,都会更新成ai。

很好理解。。。因为是没有出现的最小的,ai更小。。。

之前说过这是一个非递减的序列,所以原先mex值大于ai的也是一段连续的区间,所以我们可以找到最靠左的位置 r,使得mex[r] > a[i]。那么r 到 j - 1这段区间的mex值便 会更新为a[i]。

所以全部搞定。。。用线段树维护一下mex序列,区间更新,区间求和,然后一个查找就可以了。。。

以上是cxlove的博客的题解。

说白了,就是寻找一段区域,然后区域更新这段区域。

然后sum[1]代表全部区域的和。

#include<stdio.h>#include<iostream>#include<stdlib.h>#include<string.h>#include<algorithm>#include<vector>using namespace std;#define maxn 220000#define lmin 1#define rmax n#define lson l,(l+r)/2,rt<<1#define rson (l+r)/2+1,r,rt<<1|1#define root lmin,rmax,1#define now l,r,rt#define INF 99999999#define LL __int64vector<LL>vec[maxn];LL fail[maxn];LL mex[maxn];LL vis[maxn];LL a[maxn];LL val[maxn*4];LL sum[maxn*4];LL maxx[maxn*4];LL lazy[maxn*4];void push_up(int l,int r,int rt){    sum[rt]=sum[rt<<1]+sum[rt<<1|1];    maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);}void push_down(int l,int r,int rt){    if(lazy[rt]!=-1)    {        int mid=(l+r)/2;        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];        maxx[rt<<1]=maxx[rt<<1|1]=lazy[rt];        sum[rt<<1]=lazy[rt]*(mid-l+1);        sum[rt<<1|1]=lazy[rt]*(r-mid);        lazy[rt]=-1;    }}void creat(int l,int r,int rt){    val[rt]=sum[rt]=maxx[rt]=0;    lazy[rt]=-1;    if(l!=r)    {        creat(lson);        creat(rson);        push_up(now);        return;    }    val[rt]=sum[rt]=maxx[rt]=mex[l];}void update(int ll,int rr,LL x,int l,int r,int rt){    if(ll>r||rr<l)return;    if(ll<=l&&rr>=r)    {        lazy[rt]=x;        sum[rt]=(r-l+1)*x;        maxx[rt]=x;        return;    }    push_down(now);    update(ll,rr,x,lson);    update(ll,rr,x,rson);    push_up(now);}int querymax(LL x,int l,int r,int rt){    if(maxx[rt]<x)return INF;    if(l==r)return l;    push_down(now);    int ans=INF;    ans=querymax(x,lson);    if(ans==INF)ans=querymax(x,rson);    return ans;}int main(){    int T,n;    while(~scanf("%d",&n)&&n)    {        LL ans=0;        for(int i=0; i<=n+1; i++)        {            fail[i]=0;            vec[i].clear();        }        for(int i=1; i<=n; i++)        {            scanf("%I64d",&a[i]);            if(a[i]>n)a[i]=n+1;            vec[a[i]].push_back(i);        }        memset(vis,0,sizeof(vis));        int l=0;        for(int i=1; i<=n; i++)        {            vis[a[i]]=1;            for(l; vis[l]; l++);            mex[i]=l;            ans+=mex[i];        }        creat(root);       // cout<<ans<<endl;        int index;        for(int i=1; i<n; i++)        {            fail[a[i]]++;            if(fail[a[i]]<vec[a[i]].size())index=vec[a[i]][fail[a[i]]];            else index=n+1;            int l=querymax(a[i],root);            if(l<index)            {                update(l,index-1,a[i],root);            }            ans+=sum[1];        }        cout<<ans<<endl;    }    return 0;}



0 0