文章标题
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 ; }
相关文章推荐
- 线段树题集
- hdu1754
- HDU1394
- 敌兵布阵 (1)
- I Hate It (1)
- LCIS (2)
- A Simple Problem with Integers (2)
- Mayor's posters (3)
- Buy Tickets (3)
- 线段树
- UVA - 12532 Interval Product
- POJ 3264 Balanced Lineup
- hdu 1542 求矩形并的面积
- 关于数据结构之线段树
- poj 3225 关于集合运算
- poj 2352
- hdu1166敌兵布阵(线段树点修改)
- POJ 2352 Stars 线段树 pascal
- hdu 1698 Just A Hook 线段树的一道题
- HDU 1754 I Hate It