您的位置:首页 > 其它

文章标题

2015-09-30 22:23 288 查看
//给出长度为n的序列,s(i,j)表示
//在[i,j]区间内的数少了的最小非负数
//先考虑起点为s[1,i]的区间,发现是一个递增
//然后对于删了第一个数,那么从s[2,i]第一个大于第一个数开始到下一个
//值为a[1]的区间的所有数都为a[1]
//然后就是重复删除数字
//对于区间的更新可以用线段树做
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std ;
const int maxn = 2e5+10 ;
#define left v<<1
#define right v<<1|1
typedef long long ll ;
int vis[maxn];
int Next[maxn] ;
int last[maxn] ;
int m[maxn] ;
int a[maxn] ;
struct node
{
int l ,r ;
int ma ;
ll lazy ;
ll v ;
}tree[maxn<<2] ;
void push_down(int v)
{
if(tree[v].lazy != -1)
{
tree[left].v = tree[v].lazy*(tree[left].r-tree[left].l+1) ;
tree[right].v = tree[v].lazy*(tree[right].r - tree[right].l+1) ;
tree[left].ma = tree[right].ma = tree[v].lazy ;
tree[left].lazy = tree[right].lazy = tree[v].lazy ;
tree[v].lazy = -1 ;
}
}
void push_up(int v)
{
tree[v].v = tree[left].v + tree[right].v ;
tree[v].ma = max(tree[left].ma , tree[right].ma) ;
}
void build(int l , int r , int v)
{
tree[v].l = l ;
tree[v].r = r ;
tree[v].lazy = -1 ;
if(l == r)
{
tree[v].v = tree[v].ma = m[l] ;
return ;
}
int mid = (l + r) >> 1 ;
build(l , mid , left) ;
build(mid+1 , r, right) ;
push_up(v) ;
}
void update(int l , int r , int v , ll s)
{
if(l<=tree[v].l && tree[v].r <= r)
{
tree[v].v = s*(tree[v].r - tree[v].l+1) ;
tree[v].ma = s ;
tree[v].lazy = s ;
return  ;
}
push_down(v) ;
int mid = (tree[v].l+tree[v].r) >> 1;
if(l<=mid)update(l,r,left,s) ;
if(r>mid)update(l,r,right,s) ;
push_up(v) ;
}
ll query(int l , int r,int v)
{
if(l<=tree[v].l&&tree[v].r<=r)
return tree[v].v ;
push_down(v) ;
int mid = (tree[v].l+tree[v].r)>>1 ;
ll ans = 0 ;
if(l<=mid)ans+=query(l,r,left) ;
if(r>mid)ans+=query(l,r,right) ;
push_up(v) ;
return ans ;
}
int Find(int l,int r,int v , ll s)
{
if(tree[v].l == tree[v].r)
return tree[v].l ;
push_down(v) ;
int mid = (tree[v].l + tree[v].r)>>1 ;
int pos  = maxn;
if(l <= mid && tree[left].ma > s)
pos =  Find(l,r, left,s) ;
else if(r > mid && tree[right].ma > s)
pos = Find(l,r,right,s) ;
push_up(v) ;
return pos ;
}
int main()
{
int n ;
while(scanf("%d" , &n)&&n)
{
m[0] = 0 ;
memset(vis , 0 , sizeof(vis)) ;
for(int i = 1;i <= n;i++)
Next[i] = n + 1;
memset(last , 0 , sizeof(last)) ;
for(int i = 1;i <= n;i++)
{
scanf("%d" , &a[i]) ;
if(m[i-1]==a[i])
for(int j = a[i]+1;;j++)
{
if(!vis[j])
{
m[i] = j ;
break ;
}
}
else m[i] = m[i-1] ;
if(a[i] <= n)
{
vis[a[i]] = 1 ;
if(last[a[i]])
Next[last[a[i]]] = i ;
last[a[i]] = i ;
}
}
build(1, n , 1) ;
ll ans =  query(1 , n , 1) ;
for(int i = 1;i < n;i++)
{
if(a[i] <= n)
{
int pos = Find(i , min(Next[i],n) ,1 ,  a[i]) ;
if(pos < Next[i])
update(pos , Next[i] - 1, 1 , a[i]) ;
}
ans += query(i+1 ,n,1) ;
}
cout<<ans<<endl;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树