http://acm.hdu.edu.cn/showproblem.php?pid=4747

题意:定义一个函数mex(i,j),mex(i,j)为从i到j之间没有出现的最小的非负整数,求所有的mex(i,j)的值的和。

我们可以知道mex(i,i+1)到mex(i,i+n)的值是递增的。可以先求从mex(1,1),mex(1,2)....mex(1,n)的值,然后通过以1开始的mex推出以2开始的mex的值,以此递推下去。

使用线段树维护,删除前面的数。删掉第一个数a[1]. 那么在下一个a[1]出现前的 大于a[1]的mex值都要变成a[1]。使用线段树维护区间的值修改和区间求和。

hdu 4747 Mex_i++hdu 4747 Mex_#include_02
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <map>
  4 #include <algorithm>
  5 #define LL long long
  6 #define maxn 200001
  7 using namespace std;
  8 
  9 LL max2(LL a,LL b)
 10 {
 11     return b>a?b:a;
 12 }
 13 
 14 struct node
 15 {
 16     int l,r;
 17     int max1;
 18     LL sum;
 19     int flag;
 20 } tree[maxn*4];
 21 int a[maxn];
 22 int n;
 23 int mex[maxn];
 24 int next[maxn];
 25 
 26 void build(int i,int l,int r)
 27 {
 28     tree[i].l=l;
 29     tree[i].r=r;
 30     tree[i].flag=0;
 31     if(l==r)
 32     {
 33         tree[i].max1=mex[l];
 34         tree[i].sum=mex[l];
 35         return ;
 36     }
 37     int mid=(l+r)>>1;
 38     build(i<<1,l,mid);
 39     build(i<<1|1,mid+1,r);
 40     tree[i].max1=max2(tree[i<<1].max1,tree[i<<1|1].max1);
 41     tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
 42 }
 43 
 44 
 45 void down(int i)
 46 {
 47     if(tree[i].l==tree[i].r) return ;
 48     if(tree[i].flag)
 49     {
 50         tree[i<<1].sum=(LL)tree[i].max1*(tree[i<<1].r-tree[i<<1].l+1);
 51         tree[i<<1].max1=tree[i].max1;
 52         tree[i<<1].flag=1;
 53         tree[i<<1|1].sum=(LL)tree[i].max1*(tree[i<<1|1].r-tree[i<<1|1].l+1);
 54         tree[i<<1|1].max1=tree[i].max1;
 55         tree[i<<1|1].flag=1;
 56         tree[i].flag=0;
 57     }
 58 }
 59 
 60 void update(int i,int l,int r,int key)
 61 {
 62     if(tree[i].l==l&&tree[i].r==r)
 63     {
 64         tree[i].sum=(LL)key*(tree[i].r-tree[i].l+1);
 65         tree[i].max1=key;
 66         tree[i].flag=1;
 67         return;
 68     }
 69     down(i);
 70     int mid=(tree[i].l+tree[i].r)>>1;
 71     if(r<=mid)
 72     {
 73         update(i<<1,l,r,key);
 74     }
 75     else if(l>mid)
 76     {
 77         update(i<<1|1,l,r,key);
 78     }
 79     else
 80     {
 81         update(i<<1,l,mid,key);
 82         update(i<<1|1,mid+1,r,key);
 83     }
 84     if(tree[i].l!=tree[i].r)
 85     {
 86         tree[i].max1=max2(tree[i<<1].max1,tree[i<<1|1].max1);
 87         tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
 88    }
 89 }
 90 
 91 int get_max(int i,int key)
 92 {
 93     if(tree[i].l==tree[i].r)
 94     {
 95         return tree[i].l;
 96     }
 97     down(i);
 98     if(tree[i<<1].max1>key)
 99      return get_max(i<<1,key);
100     else  return get_max(i<<1|1,key);
101 }
102 int main()
103 {
104     while(scanf("%d",&n)!=EOF)
105     {
106         if(n==0) break;
107         for(int i=1; i<=n; i++)
108         {
109             scanf("%d",&a[i]);
110         }
111         map<int,int>q;
112         int t1=0;
113         for(int i=1; i<=n; i++)
114         {
115             q[a[i]]=1;
116             while(q.find(t1)!=q.end()) t1++;
117             mex[i]=t1;
118         }
119         q.clear();
120         for(int i=n; i>=1; i--)
121         {
122             if(q.find(a[i])==q.end()) next[i]=n+1;
123             else next[i]=q[a[i]];
124             q[a[i]]=i;
125         }
126         build(1,1,n);
127         LL ans=0;
128         for(int i=1; i<=n; i++)
129         {
130             ans+=tree[1].sum;
131             if(tree[1].max1>a[i])
132             {
133                 int ll=get_max(1,a[i]);
134                 int rr=next[i];
135                 if(ll<rr)
136                 {
137                     update(1,ll,rr-1,a[i]);
138                 }
139             }
140             update(1,i,i,0);
141         }
142         printf("%I64d\n",ans);
143     }
144     return 0;
145 }
View Code