[2013 ACM/ICPC Asia Regional Hangzhou Online J/1010]hdu 4747 Mex (线段树)

题意:

给定一个长度为 n 的非负数列,定义 mex(l, r) 为 l,r 区间里最小的没有出现的数字。

求所有 mex(l, r) 的和

分析参见 http://www.shuizilong.com/house/archives/hdu-4747-mex/

我的代码:

ExpandedBlockStart.gif
  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <vector>
  5 typedef  long  long ll;
  6  #define lson l, mid, rt << 1
  7  #define rson mid + 1, r, rt << 1 |1
  8 
  9  struct node {
 10      int mx, mi, setv;
 11     ll sum;
 12 };
 13 
 14  const  int N =  200000 +  10;
 15  int ar[N];
 16 node seg[N <<  2];
 17 
 18  bool vis[N];
 19  int idx;
 20 
 21  void Up(node& fa, node& ls, node& rs) {
 22     fa.mx = std::max(ls.mx , rs.mx);
 23     fa.sum = ls.sum + rs.sum;
 24     fa.mi = std::min(ls.mi, rs.mi);
 25 }
 26  void build( int l,  int r,  int rt) {
 27     seg[rt].setv = - 1;
 28      if (l == r) {
 29         vis[ar[l]] =  true;
 30          while (vis[idx])
 31             ++idx;
 32         seg[rt].mx = seg[rt].mi = seg[rt].sum = idx;
 33     }  else {
 34          int mid = (l + r) >>  1;
 35         build(lson);
 36         build(rson);
 37         Up(seg[rt], seg[rt <<  1], seg[rt <<  1 |  1]);
 38     }
 39 }
 40  void Down(node& fa, node& ls, node& rs,  int len) {
 41      if (~fa.setv) {
 42         ls.setv = rs.setv = ls.mx = rs.mx = ls.mi = rs.mi = fa.setv;
 43         ls.sum = (ll)(len - (len >>  1)) * fa.setv;
 44         rs.sum = (ll)(len >>  1) * fa.setv;
 45         fa.setv = - 1;
 46     }
 47 }
 48 ll query( int L,  int R,  int l,  int r,  int rt) {
 49      if (L == l && R == r)
 50          return seg[rt].sum;
 51     Down(seg[rt], seg[rt <<  1], seg[rt <<  1 |  1], r - l +  1);
 52      int mid = (l + r) >>  1;
 53      if (R <= mid)  return query(L, R, lson);
 54      else  if (L > mid)  return query(L, R, rson);
 55      else  return query(L, mid, lson) + query(mid +  1, R, rson);
 56 }
 57  void update( int L,  int R,  int v,  int l,  int r,  int rt) {
 58      if (seg[rt].mx <= v)  return ;
 59      int mid = (l + r) >>  1;
 60      if (L == l && R == r) {
 61          if (seg[rt].mi >= v) {
 62             seg[rt].mi = seg[rt].mx = seg[rt].setv = v;
 63             seg[rt].sum = (ll)(r - l +  1) * v;
 64              return ;
 65         }
 66          if (l == r) {
 67              if (seg[rt].mx > v) {
 68                 seg[rt].mi = seg[rt].mx = seg[rt].sum = v;
 69                 seg[rt].setv = - 1;
 70             }
 71              return ;
 72         }
 73          //
 74          Down(seg[rt], seg[rt <<  1], seg[rt <<  1 |  1], r - l +  1);
 75          if (R <= mid) update(L, R, v, lson);
 76          else  if (L > mid) update(L, R, v, rson);
 77          else {
 78             update(L, mid, v, lson);
 79             update(mid +  1, R, v, rson);
 80         }
 81         Up(seg[rt], seg[rt <<  1], seg[rt <<  1 |  1]);
 82          //
 83      }  else {
 84         Down(seg[rt], seg[rt <<  1], seg[rt <<  1 |  1], r - l +  1);
 85          if (R <= mid) update(L, R, v, lson);
 86          else  if (L > mid) update(L, R, v, rson);
 87          else {
 88             update(L, mid, v, lson);
 89             update(mid +  1, R, v, rson);
 90         }
 91         Up(seg[rt], seg[rt <<  1], seg[rt <<  1 |  1]);
 92     }
 93 }
 94  int n;
 95 
 96  int nex[N], hap[N];
 97 
 98  void work() {
 99      for ( int i =  1; i <= n; ++i) {
100         scanf( " %d ", &ar[i]);
101          if (ar[i] > n)
102             ar[i] = n +  1;
103     }
104     memset(vis,  0sizeof(vis));
105     idx =  0;
106     build( 1, n,  1);
107     ll ans = query( 1, n,  1, n,  1);
108 
109     memset(hap, - 1sizeof(hap));
110     memset(nex, - 1sizeof(nex));
111 
112      for ( int i =  1; i <= n; ++i) {
113          if (hap[ar[i]] == - 1)
114             hap[ar[i]] = i;
115          else {
116             nex[hap[ar[i]]] = i;
117             hap[ar[i]] = i;
118         }
119     }
120 
121      int to;
122      for ( int i =  1; i <= n -  1; ++i) {
123          if (nex[i] == - 1)
124             to = n;
125          else
126             to = nex[i] -  1;
127         update(i, to, ar[i],  1, n,  1);
128         ans = ans + query(i, n,  1, n,  1);
129     }
130     printf( " %I64d\n ", ans);
131 }
132  int main() {
133      while ( 1 == scanf( " %d ", &n)) {
134          if ( 0 == n)  break;
135         work();
136     }
137      return  0;
138 }
View Code 


CLJ有一个很诡异的map解法

ExpandedBlockStart.gif
 1 #include <vector>
 2 #include < string>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <queue>
 6 #include < set>
 7 #include <map>
 8 #include <sstream>
 9 #include <iomanip>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 #include <cmath>
14  using  namespace std;
15 typedef  long  long ll;
16 typedef  double du;
17  #define pb push_back
18  #define mp make_pair
19  #define fi first
20  #define se second
21  #define FOR(i, s, t) for(i = (s); i < (t); i++)
22  #define RFOR(i, s, t) for(i = (s)-1; i >= (t); i--)
23  const  int MAXN =  200004;
24 
25  int a[MAXN];
26  int nextSame[MAXN], next[MAXN];
27  bool vis[MAXN];
28 map< intint> s;
29 
30  int main()
31 {
32     #ifdef __FIO
33     freopen( " in.txt "" r ", stdin);
34      // freopen("out.txt", "w", stdout);
35       #endif
36      int T;
37      // scanf("%d", &T);
38       while( 1){
39          int n;
40          int i, j, k;
41          int si;
42         ll sum, tsum;
43         sum = tsum =  0;
44         scanf( " %d ", &n);
45          if(n ==  0)
46              break;
47          for(i =  0; i < n; i++){
48             scanf( " %d ", &a[i]);
49              if(a[i] > n)
50                 a[i] = n+ 1;
51         }
52          for(i =  0; i <= n+ 1; i++)
53             next[i] = n;
54          for(i = n- 1; i >=  0; i--){
55             nextSame[i] = next[a[i]];
56             next[a[i]] = i;
57         }
58         memset(vis,  0sizeof vis);
59         j =  0;
60         s.clear();
61          for(i =  0; i < n; i++){
62             vis[a[i]] =  true;
63              while(vis[j])
64                 j++;
65             tsum += j;
66             s[i] = j;
67         }
68         s[n] = n;
69         sum += tsum;
70          for(i =  0; i < n- 1; i++){
71             tsum -= s.begin()->se;
72             s[i] = - 1;
73             map< intint>::iterator it = s.lower_bound(nextSame[i]- 1);
74              if(it->se > a[i]){
75                  if(it->fi >= nextSame[i]){
76                      int temp = it->se-a[i];
77                     tsum -= (ll)temp*(nextSame[i]- 1);
78                     it--;
79                     tsum += (ll)temp*it->fi;
80                 }
81                  while(it->se >= a[i]){
82                      int temp = it->se-a[i];
83                     tsum -= (ll)temp*it->fi;
84                     s.erase(it--);
85                     tsum += (ll)temp*it->fi;
86                 }
87                 s[nextSame[i]- 1] = a[i];
88             }
89             s.erase(i);
90             sum += tsum;
91         }
92         printf( " %I64d\n ", sum);
93     }
94      return  0;
95 }
View Code 

 

转载于:https://www.cnblogs.com/hewifi/p/3329168.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值