#1:来自辣鸡的初奏——6

joyoi楼兰图腾,树状数组求逆序对的题,joyoi过不去,contesthunter过去了……

 1 #include <cstdio>
 2 #include <cstring>
 3 #define ll long long
 4 #define init(a, b) memset(a, b, sizeof(a))
 5 
 6 const int maxn = 200005;
 7 int n;
 8 int a[maxn], t[maxn];
 9 ll l[maxn], r[maxn];
10 
11 int ask(int x) {
12     int ret = 0;
13     for (; x; x -= x & (-x))    ret += t[x];
14     return ret;
15 }
16 
17 void add(int x, int cnt) {
18     for (; x <= n; x += x & (-x))
19         t[x] += cnt;
20 }
21 
22 ll All() {
23     ll ret = 0ll;
24     for (int i = 0; i < n; i++)
25         ret += l[i] * r[i];
26     return ret;
27 }
28 
29 ll solve0() {
30     init(t, 0);
31     init(l, 0);
32     init(r, 0);
33     for (int i = 0; i < n; i++) {
34         l[i] += ask(n) - ask(a[i]);
35         add(a[i], 1);
36     }
37     init(t, 0);
38     for (int i = n-1; ~i; i--) {
39         r[i] += ask(n) - ask(a[i]);
40         add(a[i], 1);
41     }
42     return All();
43 }
44 
45 ll solve1() {
46     init(t, 0);
47     init(l, 0);
48     init(r, 0);
49     for (int i = 0; i < n; i++) {
50         l[i] += ask(a[i]-1);
51         add(a[i], 1);
52     }
53     init(t, 0);
54     for (int i = n-1; ~i; i--) {
55         r[i] += ask(a[i]-1);
56         add(a[i], 1);
57     }
58     return All();
59 }
60 
61 int main() {
62     scanf("%d", &n);
63     for (int i = 0; i < n; i++) {
64         scanf("%d", &a[i]);
65     }
66     printf("%lld %lld", solve0(), solve1());
67 }
View Code

 

UVALive4329,枚举标杆是常见手段,其余的跟上一个题一样。然后发现上一个题写得过于直观可以优化。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 #define maxa 100001
 6 #define maxn 20005
 7 #define init(a, b) memset(a, b, sizeof(a))
 8 #define ll long long
 9 
10 int n, T, maxx;
11 int a[maxn], l[maxn], r[maxn];
12 int t[maxa];
13 
14 int ask(int x) {
15     int ret = 0;
16     for (; x; x -= x & -x)  ret += t[x];
17     return ret;
18 }
19 
20 void add(int x, int cnt) {
21     for (; x <= maxx; x += x & -x)  t[x] += cnt;
22 }
23 
24 ll solve() {
25     init(t, 0);
26     init(l, 0);
27     init(r, 0);  
28     for (int i = 0; i < n; i++) {
29         l[i] += ask(maxx) - ask(a[i]); 
30         add(a[i], 1);
31     }
32     init(t, 0);
33     for (int i = n-1; ~i; i--) {
34         r[i] += ask(a[i] - 1);
35         add(a[i], 1);
36     }
37 
38     ll ret = 0ll;
39     for (int i = 1; i < n-1; i++)
40         ret += (ll)l[i] * r[i] + (ll)(i-l[i]) * (n-1-i-r[i]);
41     return ret;
42 }
43 
44 int main() {
45     for (scanf("%d", &T); T; T--) {
46         maxx = -1;
47         scanf("%d", &n);
48         for (int i = 0; i < n; i++) {
49             scanf("%d", &a[i]);
50             maxx = max(maxx, a[i]);
51         }
52         printf("%lld\n", solve());
53     }
54     return 0;
55 }
View Code

 

poj3468,画一画然后把和式改写一下会把问题降维,使前缀和数组的前缀和的和(orz)只与单个下标有关,就用树状数组维护了。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cctype>
 4 #include <algorithm>
 5 using namespace std;
 6 #define ri readint()
 7 #define gc getchar()
 8 #define ll long long
 9 #define maxn 100005
10 
11 int readint() {
12     int x = 0, s = 1, c = gc;
13     while (c <= 32)    c = gc;
14     if (c == '-')    s = -1, c = gc;
15     for (; isdigit(c); c = gc)    x = x * 10 + c - 48;
16     return x * s;
17 }
18 
19 int N, Q;
20 ll sum[maxn], b[maxn][2];
21 
22 ll ask(int x, int flag) {
23     ll ret = 0ll;
24     for (; x; x -= x & -x)    ret += b[x][flag];
25     return ret;
26 }
27 
28 void add(int x, int cnt, int flag) {
29     for (; x <= N; x += x & -x)    b[x][flag] += cnt;
30 }
31 
32 int main() {
33     N = ri, Q = ri;
34     for (int i = 1; i <= N; i++) {
35         int a = ri;
36         sum[i] = sum[i-1] + a;
37     }
38     for (int i = 1; i <= Q; i++) {
39         char ch;
40         scanf("%c", &ch);
41         int a = ri, y = ri;
42         if (ch == 'Q') {
43             printf("%lld\n", sum[y] - sum[a-1] + (y+1)*ask(y, 0) - ask(y, 1) - a*ask(a-1, 0) + ask(a-1, 1));
44         } else {
45             int c = ri;
46             add(a, c, 0);
47             add(a, a*c, 1);
48             add(y+1, -c, 0);
49             add(y+1, (y+1)*(-c), 1);
50         }
51     }
52     return 0;
53 }
View Code

 

hihocoder1384,读题好吃力。倍增贪心选取。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #define ll long long
 6 #define maxn 500005
 7 using namespace std;
 8 
 9 int n, m, T, tmp;
10 ll k, a[maxn], b[maxn], c[maxn];
11 
12 void merge(int l, int mid, int r) {
13     for (int i = l, j = mid+1, k = l; k <= r; k++) {
14         if (j > r || (i <= mid && b[i] <= b[j]))    c[k] = b[i++];
15         else    c[k] = b[j++];
16     }
17 }
18 
19 ll cal(int l, int r) {
20     if (r > n)    r = n;
21     for (int i = tmp+1; i <= r; i++)    b[i] = a[i];
22     sort(b+tmp+1, b+r+1);
23     merge(l, tmp, r);
24 
25     int t = min(m, (r-l+1)/2);
26     ll ret = 0ll;
27     for (int i = 0; i < t; i++)
28         ret += (c[r-i] - c[l+i]) * (c[r-i] - c[l+i]);
29     return ret;
30 }
31 
32 int solve() {
33     int l = 1, r = 1, ans = 0;
34     tmp = 1;
35     b[1] = a[1];
36     for (; l <= n; l = r+1, ans++) {
37         int p = 1;
38         while (p) {
39             ll num = cal(l, r+p);
40 
41             if (num <= k) {
42                 tmp = r = min(r+p, n);
43                 for (int i = l; i <= r; i++)    b[i] = c[i];
44                 p <<= 1;
45             } else    p >>= 1;
46 
47             if (r == n)    break;
48         }
49     }
50 
51     return ans;
52 }
53 
54 int main() {
55     for (scanf("%d", &T); T; T--) {
56         scanf("%d%d%lld", &n, &m, &k);
57         for (int i = 1; i <= n; i++)
58             scanf("%lld", &a[i]);
59         printf("%d\n", solve());
60     }
61     return 0;
62 }
View Code

 

UVA11235,序列过于特殊,一大堆信息都能记录,然后可以套ST表。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int maxn = 1e5 + 5;
 7 const int maxnlog = 20;
 8 struct RMQ {
 9     int d[maxn][maxnlog];
10 
11     void init(int *A, int n) {
12         for (int i = 1; i <= n; i++)    d[i][0] = A[i];
13         for (int j = 1; (1<<j) <= n; j++)
14             for (int i = 1; i+(1<<j)-1 <= n; i++)
15                 d[i][j] = max(d[i][j-1], d[i+(1<<(j-1))][j-1]);
16     }
17 
18     int query(int l, int r) {
19         int k = 0;
20         while ((1<<(k+1)) <= r - l + 1)    k++;
21         return max(d[l][k], d[r-(1<<k)+1][k]);
22     }
23 }rmq;
24 
25 int n, q, a[maxn];
26 int start, t;
27 int cnt[maxn], num[maxn], left[maxn], right[maxn];
28 
29 int main() {
30     while (~scanf("%d", &n) && n) {
31         scanf("%d", &q);
32         for (int i = 1; i <= n; i++)    scanf("%d", &a[i]);
33         a[n+1] = a[n] + 1;
34         t = 0;
35         for (int i = 1; i <= n+1; i++) {
36             if (i == 1 || a[i] > a[i-1]) {
37                 if (i > 1) {
38                     cnt[++t] = i - start;
39                     for (int j = start; j < i; j++) {
40                         num[j] = t;
41                         left[j] = start;
42                         right[j] = i - 1;
43                     }
44                 }
45                 start = i;
46             }
47         }
48 
49         rmq.init(cnt, t);
50         while (q--) {
51             int a, b, ans;
52             scanf("%d%d", &a, &b);
53             if (num[a] == num[b])    ans = b - a + 1;
54             else {
55                 ans = max(right[a] - a + 1, b - left[b] + 1);
56                 if (num[a]+1 < num[b])    ans = max(ans, rmq.query(num[a]+1, num[b]-1));
57             }
58             printf("%d\n", ans);
59         }
60     }
61     return 0;
62 }
View Code

 

poj2182,本日做的最妙的题?树状数组是维护前缀和,但前缀和得自己琢磨好。然鹅最初的最初要把题目的内在本质探索明白才行。

 1 #include <cstdio>
 2 #include <cmath>
 3 #define maxn 8005
 4 
 5 int n, a[maxn];
 6 int c[maxn], h[maxn];
 7 
 8 void add(int x) {
 9     for (; x <= n; x += x&-x)    c[x]--;
10 }
11 
12 int main() {
13     scanf("%d", &n);
14     for (int i = 1; i <= n; i++) {
15         c[i]++;
16         if (i + (i & -i) <= n)    c[i + (i & -i)] += c[i];
17     }
18     a[1] = 1;
19     for (int i = 2; i <= n; i++) {
20         scanf("%d", &a[i]);
21         a[i]++;
22     }
23 
24     int t = log(n) / log(2);
25     for (int i = n; i; i--) {
26         int ans = 0, sum = 0;
27         for (int j = t; ~j; j--) {
28             int p = 1<<j;
29             if (ans + p <= n && sum + c[ans+p] < a[i]) {
30                 ans += p;
31                 sum += c[ans];
32             }
33         }
34         add(h[i] = ans+1);
35     }
36 
37     for (int i = 1; i <= n; i++)    printf("%d\n", h[i]);
38     return 0;
39 }
View Code

 

posted @ 2019-01-30 09:59  AlphaWA  阅读(155)  评论(0编辑  收藏  举报