HDU 4747 Mex (2013杭州网络赛1010题,线段树)

Mex

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 623    Accepted Submission(s): 209

Problem Description Mex is a function on a set of integers, which is universally used for impartial game theorem. For a non-negative integer set S, mex(S) is defined as the least non-negative integer which is not appeared in S. Now our problem is about mex function on a sequence.

Consider a sequence of non-negative integers {ai}, we define mex(L,R) as the least non-negative integer which is not appeared in the continuous subsequence from aL to aR, inclusive. Now we want to calculate the sum of mex(L,R) for all 1 <= L <= R <= n.  

 

Input The input contains at most 20 test cases.

For each test case, the first line contains one integer n, denoting the length of sequence.

The next line contains n non-integers separated by space, denoting the sequence.

(1 <= n <= 200000, 0 <= ai <= 10^9)

The input ends with n = 0.  

 

Output For each test case, output one line containing a integer denoting the answer.  

 

Sample Input 3 0 1 3 5 1 0 2 0 1 0  

 

Sample Output 5 24
Hint For the first test case: mex(1,1)=1, mex(1,2)=2, mex(1,3)=2, mex(2,2)=0, mex(2,3)=0,mex(3,3)=0. 1 + 2 + 2 + 0 +0 +0 = 5.  

 

Source
2013 ACM/ICPC Asia Regional Hangzhou Online  

 

Recommend liuyiding  

 

 

题目定义了mex(i,j)表示,没有在i到j之间出现的最小的非负整数。

 

 

求所有组合的i,j(i<=j)的和

就是求mex(1,1) + mex(1,2)+….+mex(1,n)

+mex(2,2) + mex(2,3) + …mex(2,n)

+mex(3,3) + mex(3,4)+…+mex(3,n)

+ mex(n,n)

 

可以知道mex(i,i),mex(i,i+1)到mex(i,n)是递增的。

 

首先很容易求得mex(1,1),mex(1,2)……mex(1,n)

因为上述n个数是递增的。

 

然后使用线段树维护,需要不断删除前面的数。

比如删掉第一个数a[1]. 那么在下一个a[1]出现前的 大于a[1]的mex值都要变成a[1]

因为是单调递增的,所以找到第一个 mex > a[1]的位置,到下一个a[1]出现位置,这个区间的值变成a[1].

 

然后需要线段树实现区间修改和区间求和。

 

  1 /* ***********************************************
  2 Author        :kuangbin
  3 Created Time  :2013-9-17 21:15:02
  4 File Name     :G:\2013ACM练习\2013网络赛\2013杭州网络赛\1010.cpp
  5 ************************************************ */
  6 
  7 #pragma comment(linker, "/STACK:1024000000,1024000000")
  8 #include <stdio.h>
  9 #include <string.h>
 10 #include <iostream>
 11 #include <algorithm>
 12 #include <vector>
 13 #include <queue>
 14 #include <set>
 15 #include <map>
 16 #include <string>
 17 #include <math.h>
 18 #include <stdlib.h>
 19 #include <time.h>
 20 using namespace std;
 21 
 22 const int MAXN = 200010;
 23 struct Node
 24 {
 25     int l,r;
 26     long long sum;//区间和
 27     int mx;//最大值
 28     int lazy;//懒惰标记,表示赋值为相同的
 29 }segTree[MAXN*3];
 30 void push_up(int i)
 31 {
 32     if(segTree[i].l == segTree[i].r)return;
 33     segTree[i].sum = segTree[i<<1].sum + segTree[(i<<1)|1].sum;
 34     segTree[i].mx = max(segTree[i<<1].mx,segTree[(i<<1)|1].mx);
 35 }
 36 void Update_Same(int i,int v)
 37 {
 38     segTree[i].sum = (long long)v*(segTree[i].r - segTree[i].l + 1);
 39     segTree[i].mx = v;
 40     segTree[i].lazy = 1;
 41 }
 42 void push_down(int i)
 43 {
 44     if(segTree[i].l == segTree[i].r)return;
 45     if(segTree[i].lazy)
 46     {
 47         Update_Same(i<<1,segTree[i].mx);
 48         Update_Same((i<<1)|1,segTree[i].mx);
 49         segTree[i].lazy = 0;
 50     }
 51 }
 52 int mex[MAXN];
 53 void Build(int i,int l,int r)
 54 {
 55     segTree[i].l = l;
 56     segTree[i].r = r;
 57     segTree[i].lazy = 0;
 58     if(l == r)
 59     {
 60         segTree[i].mx = mex[l];
 61         segTree[i].sum = mex[l];
 62         return;
 63     }
 64     int mid = (l + r)>>1;
 65     Build(i<<1,l,mid);
 66     Build((i<<1)|1,mid+1,r);
 67     push_up(i);
 68 }
 69 //将区间[l,r]的数都修改为v
 70 void Update(int i,int l,int r,int v)
 71 {
 72     if(segTree[i].l == l && segTree[i].r == r)
 73     {
 74         Update_Same(i,v);
 75         return;
 76     }
 77     push_down(i);
 78     int mid = (segTree[i].l + segTree[i].r)>>1;
 79     if(r <= mid)
 80     {
 81         Update(i<<1,l,r,v);
 82     }
 83     else if(l > mid)
 84     {
 85         Update((i<<1)|1,l,r,v);
 86     }
 87     else
 88     {
 89         Update(i<<1,l,mid,v);
 90         Update((i<<1)|1,mid+1,r,v);
 91     }
 92     push_up(i);
 93 }
 94 //得到值>= v的最左边位置
 95 int Get(int i,int v)
 96 {
 97     if(segTree[i].l == segTree[i].r)
 98         return segTree[i].l;
 99     push_down(i);
100     if(segTree[i<<1].mx > v)
101         return Get(i<<1,v);
102     else return Get((i<<1)|1,v);
103 }
104 int a[MAXN];
105 map<int,int>mp;
106 int next[MAXN];
107 int main()
108 {
109     //freopen("in.txt","r",stdin);
110     //freopen("out.txt","w",stdout);
111     int n;
112     while(scanf("%d",&n) && n)
113     {
114         for(int i = 1;i <= n;i++)
115             scanf("%d",&a[i]);
116         mp.clear();
117         int tmp = 0;
118         for(int i = 1;i <= n;i++)
119         {
120             mp[a[i]] = 1;
121             while(mp.find(tmp) != mp.end())tmp++;
122             mex[i] = tmp;
123         }
124         mp.clear();
125         for(int i = n;i >= 1;i--)
126         {
127             if(mp.find(a[i]) == mp.end())next[i] = n+1;
128             else next[i] = mp[a[i]];
129             mp[a[i]] = i;
130         }
131         Build(1,1,n);
132         long long sum = 0;
133         for(int i = 1;i <= n;i++)
134         {
135             sum += segTree[1].sum;
136             if(segTree[1].mx > a[i])
137             {
138                 int l = Get(1,a[i]);
139                 int r = next[i];
140                 if(l < r)
141                     Update(1,l,r-1,a[i]);
142             }
143             Update(1,i,i,0);
144         }
145         printf("%I64d\n",sum);
146 
147     }
148     return 0;
149 }

 

 

 

 

 

 

 

 

 

 

 

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/kuangbin/p/3327674.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞