传送门:HDU4747
【题意】给出一个N(<=200000)长的序列,定义一个MEX(L,R)表示区间[L,R]中没有出现的最小非负整数,求出序列所有MEX()之和。
【分析】首先很容易看出对于L固定的区间,R的向右是单调递增的,这样可以先预处理出第一行[L,1][L,2][L,3]…[L,N],把它放入线段树,然后观察左边每删掉一个数(也就是下一个L)对后面的影响,当删除a[i]后,一直到下一个a[i]出现前的大于a[i]区间答案都要变为a[i],下一个出现的a[i]可以预处理出来,然后由于是递增的,所以只要在线段树二分找到第一个大于a[i]的作为左端点x,下一个出现的a[i]前一个作为右端点y,把[x,y]全部更新为a[i]即可。对于预处理,我把它离散化了(需要注意连续离散两个之间差>1的情况)。看了bin神直接用map的,map更加简单呀。
【AC CODE】1950ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 200000+10;
int a[MAXN],num[MAXN],sot[MAXN<<1],cnt;
int mhash(int v){return lower_bound(sot,sot+cnt,v)-sot;}
int inline id(int x, int y){return x+y|x!=y;}
int sz[MAXN<<2];
void add(int x, int y, int p)
{
if(x == y)
{
sz[id(x,y)] = 1;
return;
}
int m = (x+y)>>1;
if(p <= m) add(x,m,p);
else add(m+1,y,p);
sz[id(x,y)] = sz[id(x,m)]+sz[id(m+1,y)];
}
int query(int x, int y)
{
if(x == y) return sot[x];
int m = (x+y)>>1;
if(sz[id(x,m)] < m-x+1) return query(x,m);
return query(m+1,y);
}
int d[MAXN],mx[MAXN],n;
LL sum[MAXN<<1],st[MAXN<<1];
void push_down(int x, int y, int m)
{
int u = id(x,y);
if(~st[u])
{
int l = id(x,m),r = id(m+1,y);
st[l] = st[r] = st[u];
sum[l] = (m-x+1)*st[u];sum[r] = (y-m)*st[u];
mx[l] = mx[r] = st[u];
st[u] = -1;
}
}
void push_up(int x, int y, int m)
{
int u = id(x,y),l = id(x,m),r = id(m+1,y);
sum[u] = sum[l]+sum[r];
mx[u] = max(mx[l],mx[r]);
}
void bulid(int x, int y)
{
if(x == y)
{
sum[id(x,y)] = mx[id(x,y)] = d[x];
return;
}
int m = (x+y)>>1;
bulid(x,m);
bulid(m+1,y);
push_up(x,y,m);
}
void update(int x, int y, int ql, int qr, int v)
{
if(ql <= x && y <= qr)
{
int u = id(x,y);
sum[u] = v*(y-x+1);
mx[u] = v,st[u] = v;
return;
}
int m = (x+y)>>1;
push_down(x,y,m);
if(ql <= m) update(x,m,ql,qr,v);
if(qr > m) update(m+1,y,ql,qr,v);
push_up(x,y,m);
}
int find_ft(int x, int y, int v)
{
if(x == y) return x+(v>sum[id(x,y)]);
int m = (x+y)>>1,ans;
push_down(x,y,m);
if(v < mx[id(x,m)]) ans = find_ft(x,m,v);
else ans = find_ft(m+1,y,v);
push_up(x,y,m);
return ans;
}
int nxt[MAXN],la[MAXN<<1];
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
while(~scanf("%d", &n) && n)
{
rep(i,0,n) scanf("%d", &a[i]), num[i] = a[i];
num[n] = 0;
sort(num,num+n+1);
cnt = 1;
sot[0] = num[0];
rep(i,0,n+1)
{
if(num[i] != num[i-1])
{
sot[cnt++] = num[i];
if(num[i]-num[i-1] > 1)
{
sot[cnt++] = num[i-1]+1;
swap(sot[cnt-1],sot[cnt-2]);
}
}
}
sot[cnt] = sot[cnt-1]+1;
cnt++;
clc(sz,0);
clc(la,-1);
rep(i,0,n) nxt[i] = n-1;
rep(i,0,n)
{
int h = mhash(a[i]);
add(0,cnt-1,h);
d[i] = query(0,cnt-1);
if(~la[h]) nxt[la[h]] = i-1;
la[h] = i;
}
clc(st,-1);
bulid(0,n-1);
LL ans = 0;
rep(i,0,n)
{
ans += sum[id(0,n-1)];
int y = nxt[i];
int x = find_ft(0,n-1,a[i]);
update(0,n-1,0,i,0);
if(x > y) continue;
update(0,n-1,x,y,a[i]);
}
printf("%I64d\n", ans);
}
return 0;
}