Mex(线段树的巧妙应用)

题目要求求某段区间第一个没有出现的数(0,1,2,3.。。。) ,对于所有的区间,我们把这样的数加起来最后得到一个结果。

首先,我们要求出这样的数,然后还得列举出所有的区间,复杂度太大了。

换种思路,我们定住L,是不是一次性能求出所有的R所得出的结果,这就用到线段树的性质了,因为在移动L的过程中,移一步只变化一个数,那么就可以用线段树进行维护。

首先求出[1,R] 以1为左端的所有区间的情况,记录每个点也就是1到那个点的这段区间值sum[i],以这个值建一颗树,那么在L向前移动的时候,每次丢掉一个数a[i-1], 因为少了这一个数,肯定后面有部分区间是变化的,有部分是不变化的,从这点开始向后找第一个与a[i-1]值相等的数的位置p,那么这个位置后面的sum肯定不会变化,因为丢掉的数又补上了。

那么就可以只考虑,从i位置到p这段里面的sum,如果原先的sum本来就比a[i-1]小,那说明a[i-1]的减少不影响它的值,所以不用改变,而所有大于a[i-1]的值将都变为a[i-1],这样更新一下,求和就可以了。

  1 #include 
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 #include
  9 #include<set>
 10 #include
 11 using namespace std;
 12 //#pragma comment(linker, "/STACK:1024000000,1024000000")
 13 #define N 200010
 14 #define LL __int64
 15 #define INF 0xfffffff
 16 const double eps = 1e-8;
 17 const double pi = acos(-1.0);
 18 const double inf = ~0u>>2;
 19 vector<int>po[N];
 20 map<int,int>f;
 21 LL s[N<<2];
 22 int tm[N<<2];
 23 LL lz[N<<2];
 24 int sum[N];
 25 int p[N],a[N];
 26 bool vis[N];
 27 void up(int w)
 28 {
 29     s[w] = s[w<<1]+s[w<<1|1];
 30     tm[w] = max(tm[w<<1],tm[w<<1|1]);
 31     //cout<
 32 }
 33 void down(int w,int m)
 34 {
 35     if(lz[w]!=-1)
 36     {
 37         tm[w<<1] = tm[w<<1|1] = lz[w];
 38         lz[w<<1] = lz[w<<1|1] = lz[w];
 39         s[w<<1] = lz[w]*(m-m/2);
 40         s[w<<1|1] = lz[w]*(m/2);
 41         lz[w] = -1;
 42         //cout<
 43     }
 44 }
 45 void build(int l,int r,int w)
 46 {
 47     if(l==r)
 48     {
 49         s[w] = sum[l];
 50         tm[w] = sum[l];
 51         return ;
 52     }
 53     int m = (l+r)>>1;
 54     build(l,m,w<<1);
 55     build(m+1,r,w<<1|1);
 56     up(w);
 57 }
 58 void update(int a,int b,int d,int l,int r,int w)
 59 {
 60     if(a<=l&&b>=r)
 61     {
 62         s[w] = (LL)d*(r-l+1);
 63         tm[w] = d;
 64         lz[w] = d;
 65         //cout<
 66         return ;
 67     }
 68     int m = (l+r)>>1;
 69     down(w,r-l+1);
 70     if(a<=m) update(a,b,d,l,m,w<<1);
 71     if(b>m) update(a,b,d,m+1,r,w<<1|1);
 72     up(w);
 73 }
 74 int find(int k,int l,int r,int w)
 75 {
 76     // cout<
 77     if(l==r)
 78     {
 79         //cout<
 80         return l;
 81     }
 82     int m = (l+r)>>1;
 83     down(w,r-l+1);
 84     if(tm[w<<1]>k)
 85         return find(k,l,m,w<<1);
 86     else
 87         return find(k,m+1,r,w<<1|1);
 88 }
 89 LL query(int a,int b,int l,int r,int w)
 90 {
 91     if(a<=l&&b>=r)
 92     {
 93         return s[w];
 94     }
 95     int m = (l+r)>>1;
 96     LL res = 0;
 97     down(w,r-l+1);
 98     if(a<=m)
 99         res+=query(a,b,l,m,w<<1);
100     if(b>m)
101         res+=query(a,b,m+1,r,w<<1|1);
102     return res;
103 }
104 int main()
105 {
106     int n,i;
107     while(scanf("%d",&n)&&n)
108     {
109         f.clear();
110         memset(p,0,sizeof(p));
111         memset(vis,0,sizeof(vis));
112         memset(lz,-1,sizeof(lz));
113         for(i = 1; i <= n ; i++)
114             po[i].clear();
115         int g = 0;
116         for(i = 1; i <= n; i++)
117         {
118             scanf("%d",&a[i]);
119             if(!f[a[i]]) f[a[i]] = ++g;
120             po[f[a[i]]].push_back(i);
121         }
122         int o = 0;
123         for(i = 1; i <= n ; i++)
124         {
125             if(a[i]<N)
126                 vis[a[i]] = 1;
127             if(a[i]1])
128                 sum[i] = sum[i-1];
129             else
130             {
131                 while(vis[o])
132                     o++;
133                 sum[i] = o;
134             }
135         }
136         LL ans=0;
137         build(1,n,1);
138         ans+=s[1];
139         //cout<
140         p[f[a[1]]] = 1;
141         for(i = 2; i <= n ; i++)
142         {
143             int k;
144             int mk = f[a[i-1]];
145             if(p[mk]<po[mk].size())
146             {
147                 k = po[mk][p[mk]]-1;
148                 //cout<149                 //p[mk]++;
150             }
151             else k = n;
152             update(1,i-1,0,1,n,1);
153             int fk;
154             if(tm[1]>a[i-1])
155             {
156                 fk = find(a[i-1],1,n,1);
157                     update(fk,k,a[i-1],1,n,1);
158             }
159             ans+=query(i,n,1,n,1);
160            // cout<161            //cout<162             //cout<163             //if(a[i]!=a[i-1])
164             p[f[a[i]]]++;
165         }
166         cout<endl;
167     }
168     return 0;
169 }
View Code

 

 

转载于:https://www.cnblogs.com/shangyu/p/3765947.html

你可能感兴趣的:(Mex(线段树的巧妙应用))