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 }
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 ", solve()); 53 } 54 return 0; 55 }
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 ", 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 }
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 ", solve()); 60 } 61 return 0; 62 }
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 ", ans); 59 } 60 } 61 return 0; 62 }
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 ", h[i]); 38 return 0; 39 }