B.Mayor’s posters

POJ2528
题目大意:

D.Count Color

POJ2777
题目大意:长为

L

(

L

1

0

5

)

L( L\leq10^5)

L(L≤105)的序列,每个点上可以有

T

(

T

30

)

T(T\leq30)

T(T≤30)种颜色以供染色(整个序列最开始都为颜色1),

O

(

O

1

0

5

)

O(O\leq10^5)

O(O≤105)次操作:

C

C

C

a

a

a

b

b

b

c

c

c:

[

a

,

b

]

[a,b]

[a,b]染上颜色

c

c

c

P

P

P

a

a

a

b

b

b:查询

[

a

,

b

]

[a,b]

[a,b]上共有几种颜色
思路:因为

T

T

T很小,所以我们可以把颜色集合进行状态压缩,

p

u

s

h

u

p

pushup

pushup的时候直接取两个儿子的并即可,懒标记直接设为仅有对应颜色的集合即可。复杂度

O

(

(

L

+

O

)

l

o

g

L

)

O((L+O)logL)

O((L+O)logL)。此外注意本题

a

a

a可能大于

b

b

b。
代码:

  1. #include<bits/stdc++.h>
  2. #include<unordered_map>
  3. #include<unordered_set>
  4. using namespace std;
  5. typedef long long LL;
  6. typedef unsigned long long ULL;
  7. typedef pair<LL, int> PII;
  8. //#define int LL
  9. #define lc p*2+1
  10. #define rc p*2+2
  11. #define endl '\n'
  12. #define inf 0x3f3f3f3f
  13. #define INF 0x3f3f3f3f3f3f3f3f
  14. #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  15. #pragma warning(disable :4996)
  16. const double eps = 1e-8;
  17. const LL mod = 1000000007;
  18. const LL MOD = 998244353;
  19. const int maxn = 100010;
  20. struct node {
  21. int l, r, dat, lazy;
  22. };
  23. node tr[maxn * 4];
  24. void build(int p, int l, int r)
  25. {
  26. tr[p].l = l, tr[p].r = r, tr[p].lazy = 0;
  27. if (l + 1 == r)
  28. {
  29. tr[p].dat = 1;
  30. return;
  31. }
  32. int mid = (l + r) / 2;
  33. build(lc, l, mid), build(rc, mid, r);
  34. tr[p].dat = tr[lc].dat | tr[rc].dat;
  35. }
  36. void pushdown(int p)
  37. {
  38. if (tr[p].lazy)
  39. {
  40. tr[lc].dat = tr[rc].dat = tr[lc].lazy = tr[rc].lazy = tr[p].lazy;
  41. tr[p].lazy = 0;
  42. }
  43. }
  44. void modify(int p, int l, int r, int d)
  45. {
  46. if (tr[p].l >= l && tr[p].r <= r)
  47. {
  48. tr[p].dat = tr[p].lazy = 1 << d;
  49. return;
  50. }
  51. pushdown(p);
  52. int mid = (tr[p].l + tr[p].r) / 2;
  53. if (l < mid)
  54. modify(lc, l, r, d);
  55. if (r > mid)
  56. modify(rc, l, r, d);
  57. tr[p].dat = tr[lc].dat | tr[rc].dat;
  58. }
  59. int query(int p, int l, int r)
  60. {
  61. if(tr[p].l >= l && tr[p].r <= r)
  62. return tr[p].dat;
  63. pushdown(p);
  64. int mid = (tr[p].l + tr[p].r) / 2;
  65. if (r <= mid)
  66. return query(lc, l, r);
  67. if (l >= mid)
  68. return query(rc, l, r);
  69. return query(lc, l, mid) | query(rc, mid, r);
  70. }
  71. int L, T, O;
  72. void solve()
  73. {
  74. build(0, 1, L + 1);
  75. char t;
  76. int a, b, c;
  77. for (int i = 1; i <= O; i++)
  78. {
  79. cin >> t;
  80. if (t == 'C')
  81. {
  82. cin >> a >> b >> c;
  83. int l = min(a, b), r = max(a, b);
  84. modify(0, l, r + 1, c - 1);
  85. }
  86. else
  87. {
  88. cin >> a >> b;
  89. int l = min(a, b), r = max(a, b);
  90. int num = query(0, l, r + 1), ans = 0;
  91. for (int i = 0; i < T; i++)
  92. ans += (num >> i) & 1;
  93. cout << ans << endl;
  94. }
  95. }
  96. }
  97. int main()
  98. {
  99. IOS;
  100. cin >> L >> T >> O;
  101. solve();
  102. return 0;
  103. }
E.Who Gets the Most Candies?

POJ2886
题目大意:

N

N

N个人围一圈,每个人有

A

[

i

]

A[i]

A[i],表示这个人沿顺时针

(

A

[

i

]

>

0

)

(A[i]>0)

(A[i]>0)或逆时针

(

A

[

i

]

<

0

)

(A[i]<0)

(A[i]<0)方向数的第

A

[

i

]

|A[i]|

∣A[i]∣个人是下一个要退出的,每次游戏从第

K

K

K个人开始,退出的次序

r

n

k

rnk

rnk的约束个数就是获得的糖果数,问谁获得糖果最多,有多个则输出先退出的。

思路:

i

i

i以内的约数最多的最小数字可以用倍数法

O

(

N

l

o

g

N

)

O(NlogN)

O(NlogN)预处理出来,之后对于每轮游戏直接模拟即可,用

B

I

T

BIT

BIT来维护一下各个位置上的人有没有退出,在

B

I

T

BIT

BIT上二分可以求得剩下的人中相对排名对应的原始位置。

代码:

  1. #include<iostream>
  2. #include<string>
  3. #include<stack>
  4. #include<queue>
  5. #include<vector>
  6. #include<algorithm>
  7. #include<cstring>
  8. #include<cmath>
  9. #include<map>
  10. #include<set>
  11. #include<utility>
  12. #include<cstdio>
  13. using namespace std;
  14. typedef long long LL;
  15. typedef unsigned long long ULL;
  16. typedef pair<int, int> PII;
  17. //#define int LL
  18. #define endl '\n'
  19. #define inf 0x3f3f3f3f
  20. #define INF 0x3f3f3f3f3f3f3f3f
  21. #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  22. #pragma warning(disable :4996)
  23. const double eps = 1e-8;
  24. const LL mod = 1000000007;
  25. const LL MOD = 998244353;
  26. const int maxn = (1 << 19) + 10;
  27. int cnt[maxn], S[maxn];
  28. int N, K;
  29. string name[maxn];
  30. int num[maxn], dat[maxn], n;
  31. void add(int i, int x)
  32. {
  33. while (i <= (1 << 19))
  34. {
  35. dat[i] += x;
  36. i += i & (-i);
  37. }
  38. }
  39. int sum(int i)
  40. {
  41. int ans = 0;
  42. while (i > 0)
  43. {
  44. ans += dat[i];
  45. i -= i & (-i);
  46. }
  47. return ans;
  48. }
  49. int getpos(int rk)
  50. {
  51. int k = 0, s = 0;
  52. for (int i = 18; i >= 0; i--)
  53. {
  54. int t = k + (1 << i);
  55. if (s + dat[t] < rk)
  56. {
  57. k = t;
  58. s += dat[t];
  59. }
  60. }
  61. return k + 1;
  62. }
  63. void init()
  64. {
  65. for (int i = 1; i <= 5e5; i++)
  66. {
  67. for (int j = i; j <= 5e5; j += i)
  68. cnt[j]++;
  69. }
  70. for (int i = 1; i <= 5e5; i++)
  71. {
  72. if (cnt[i] > cnt[S[i - 1]])
  73. S[i] = i;
  74. else
  75. S[i] = S[i - 1];
  76. }
  77. }
  78. void solve()
  79. {
  80. string ans1;
  81. int ord = 1, lst = N - 1, ans2 = cnt[S[N]], rnk = K;
  82. int pos = getpos(rnk), start;
  83. while (true)
  84. {
  85. int A = num[pos];
  86. ans1 = name[pos];
  87. if (ord == S[N])
  88. break;
  89. add(pos, -1);
  90. if (A > 0)
  91. {
  92. rnk = (rnk - 1 + A) % lst;
  93. if (rnk == 0)
  94. rnk = lst;
  95. pos = getpos(rnk);
  96. }
  97. else
  98. {
  99. rnk = ((rnk + A) % lst + lst) % lst;
  100. if (rnk == 0)
  101. rnk = lst;
  102. pos = getpos(rnk);
  103. }
  104. ord++;
  105. lst--;
  106. }
  107. cout << ans1 << ' ' << ans2 << endl;
  108. }
  109. int main()
  110. {
  111. IOS;
  112. init();
  113. while (cin >> N >> K)
  114. {
  115. memset(dat, 0, sizeof(dat));
  116. for (int i = 1; i <= N; i++)
  117. {
  118. cin >> name[i] >> num[i];
  119. add(i, 1);
  120. }
  121. solve();
  122. }
  123. return 0;
  124. }
F.花神游历各国

LOJ10128
题目大意:
长为

N

(

N

1

0

5

)

N(N\leq10^5)

N(N≤105)的序列,各元素

0

a

i

1

0

9

0\leq a_{i}\leq10^9

0≤ai​≤109,

M

(

M

2

×

1

0

5

)

M(M\leq2\times10^5)

M(M≤2×105)
次操作:

1

1

1

l

l

l

r

r

r:

[

l

,

r

]

[l,r]

[l,r]内所有元素开根号向下取整

2

2

2

l

l

l

r

r

r:询问

[

l

,

r

]

[l,r]

[l,r]内所有元素和

(

1

l

r

N

)

(1\leq l\leq r\leq N)

(1≤l≤r≤N)

思路:
直接向区间加上一个数那样用懒标记处理取平方根显然没有办法维护,注意到

1

0

9

10^9

109内的数最多操作6次就会变为1,而对1和0本身取根号是没有变化的,于是我们可以直接对每个区间修改暴力地进行单点修改,每个节点记录所辖区间内0与1的个数,如果全部是0或者1,那么之后就不去这个区间做修改,这样每个数最多被修改6次,每次修改

O

(

l

o

g

N

)

O(logN)

O(logN),总的复杂度还是

O

(

(

N

+

M

)

l

o

g

N

)

O((N+M)logN)

O((N+M)logN)

代码:

  1. #include<bits/stdc++.h>
  2. #include<unordered_map>
  3. #include<unordered_set>
  4. using namespace std;
  5. typedef long long LL;
  6. typedef unsigned long long ULL;
  7. typedef pair<LL, int> PII;
  8. #define int LL
  9. #define lc p*2+1
  10. #define rc p*2+2
  11. #define endl '\n'
  12. #define inf 0x3f3f3f3f
  13. #define INF 0x3f3f3f3f3f3f3f3f
  14. #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  15. #pragma warning(disable :4996)
  16. const double eps = 1e-8;
  17. const LL mod = 1000000007;
  18. const LL MOD = 998244353;
  19. const int maxn = 100010;
  20. struct node {
  21. int l, r, dat;
  22. int cnt;//区间<=1之个数
  23. };
  24. int N, M;
  25. int A[maxn];
  26. node tr[maxn * 4];
  27. void build(int p, int l, int r)
  28. {
  29. tr[p].l = l, tr[p].r = r, tr[p].cnt = 0;
  30. if (l + 1 == r)
  31. {
  32. tr[p].dat = A[l];
  33. if (A[l] <= 1)
  34. tr[p].cnt = 1;
  35. return;
  36. }
  37. int mid = (tr[p].l + tr[p].r) / 2;
  38. build(lc, l, mid), build(rc, mid, r);
  39. tr[p].dat = tr[lc].dat + tr[rc].dat;
  40. tr[p].cnt = tr[lc].cnt + tr[rc].cnt;
  41. }
  42. void modify(int p, int l, int r)
  43. {
  44. if (tr[p].cnt == tr[p].r - tr[p].l)//该区间不用修改
  45. return;
  46. if (tr[p].l + 1 == tr[p].r)
  47. {
  48. tr[p].dat = floor(sqrt(tr[p].dat));
  49. if (tr[p].dat <= 1)
  50. tr[p].cnt = 1;
  51. return;
  52. }
  53. int mid = (tr[p].l + tr[p].r) / 2;
  54. if (l < mid)
  55. modify(lc, l, r);
  56. if (r > mid)
  57. modify(rc, l, r);
  58. tr[p].dat = tr[lc].dat + tr[rc].dat;
  59. tr[p].cnt = tr[lc].cnt + tr[rc].cnt;
  60. }
  61. int query(int p, int l, int r)
  62. {
  63. if (tr[p].l >= l && tr[p].r <= r)
  64. return tr[p].dat;
  65. int mid = (tr[p].l + tr[p].r) / 2;
  66. if (r <= mid)
  67. return query(lc, l, r);
  68. if (l >= mid)
  69. return query(rc, l, r);
  70. return query(lc, l, mid) + query(rc, mid, r);
  71. }
  72. void solve()
  73. {
  74. build(0, 1, N + 1);
  75. cin >> M;
  76. int x, l, r;
  77. for (int i = 1; i <= M; i++)
  78. {
  79. cin >> x;
  80. if (x == 1)
  81. {
  82. cin >> l >> r;
  83. int a = min(l, r), b = max(l, r);
  84. cout << query(0, a, b + 1) << endl;
  85. }
  86. else
  87. {
  88. cin >> l >> r;
  89. int a = min(l, r), b = max(l, r);
  90. modify(0, a, b + 1);
  91. }
  92. }
  93. }
  94. signed main()
  95. {
  96. IOS;
  97. cin >> N;
  98. for (int i = 1; i <= N; i++)
  99. cin >> A[i];
  100. solve();
  101. return 0;
  102. }
I.二逼平衡树

luoguP3380/LOJ106
题目大意:

思路:
树套树模板题,下标线段树中每个节点用一个动态开点权值线段树维护其区间内的元素,时空都是

O

(

N

l

o

g

2

N

)

O(Nlog^2N)

O(Nlog2N),
代码:

  1. #include<bits/stdc++.h>
  2. #include<unordered_map>
  3. #include<unordered_set>
  4. using namespace std;
  5. typedef long long LL;
  6. typedef unsigned long long ULL;
  7. typedef pair<LL, int> PII;
  8. //#define int LL
  9. #define lch p*2+1
  10. #define rch p*2+2
  11. #define endl '\n'
  12. #define inf 0x3f3f3f3f
  13. #define INF 0x3f3f3f3f3f3f3f3f
  14. #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  15. #pragma warning(disable :4996)
  16. const double eps = 1e-8;
  17. const LL mod = 1000000007;
  18. const LL MOD = 998244353;
  19. const int maxn = 50010;
  20. const int SIZE = 17000000;//注意大小
  21. int totb = 0;
  22. struct nodeb {
  23. int dat, lc, rc;
  24. };
  25. nodeb trb[SIZE];//内层权值线段树,动态开点
  26. struct nodea {
  27. int root, l, r;
  28. };
  29. nodea tra[maxn * 4];//外层常规下标线段树
  30. //a:外层树操作,b:内层树操作
  31. int buildb()
  32. {
  33. ++totb;
  34. trb[totb].dat = trb[totb].lc = trb[totb].rc = 0;
  35. return totb;
  36. }
  37. void modifyb(int p, int l, int r, int val, int delta)
  38. {
  39. if (l + 1 == r)
  40. {
  41. trb[p].dat += delta;
  42. return;
  43. }
  44. int mid = (l + r) / 2;
  45. if (val < mid)
  46. {
  47. if (!trb[p].lc)
  48. trb[p].lc = buildb();
  49. modifyb(trb[p].lc, l, mid, val, delta);
  50. }
  51. else
  52. {
  53. if (!trb[p].rc)
  54. trb[p].rc = buildb();
  55. modifyb(trb[p].rc, mid, r, val, delta);
  56. }
  57. trb[p].dat = trb[trb[p].lc].dat + trb[trb[p].rc].dat;
  58. }
  59. int rankb(int p, int l, int r, int x)
  60. {
  61. if (p == 0 || l + 1 == r)
  62. return 0;
  63. int mid = (l + r) / 2;
  64. if (x >= mid)
  65. return trb[trb[p].lc].dat + rankb(trb[p].rc, mid, r, x);
  66. else
  67. return rankb(trb[p].lc, l, mid, x);
  68. }
  69. int N, M, A[maxn];
  70. void builda(int p, int l, int r)
  71. {
  72. tra[p].root = buildb();
  73. tra[p].l = l, tra[p].r = r;
  74. if (l + 1 == r)
  75. {
  76. modifyb(tra[p].root, -1e8, 1e8 + 10, A[l], 1);
  77. return;
  78. }
  79. int mid = (l + r) / 2;
  80. builda(lch, l, mid), builda(rch, mid, r);
  81. for (int i = l; i < r; i++)
  82. modifyb(tra[p].root, -1e8, 1e8 + 10, A[i], 1);
  83. }
  84. void modifya(int p, int pos, int x)
  85. {
  86. modifyb(tra[p].root, -1e8, 1e8 + 10, A[pos], -1);
  87. modifyb(tra[p].root, -1e8, 1e8 + 10, x, 1);
  88. if (tra[p].l + 1 == tra[p].r)
  89. return;
  90. int mid = (tra[p].l + tra[p].r) / 2;
  91. if (pos < mid)
  92. modifya(lch, pos, x);
  93. else
  94. modifya(rch, pos, x);
  95. }
  96. int ranka(int p, int l, int r, int x)//求出[l,r)内小于x的数的个数
  97. {
  98. if (tra[p].l >= l && tra[p].r <= r)
  99. return rankb(tra[p].root, -1e8, 1e8 + 10, x);
  100. int mid = (tra[p].l + tra[p].r) / 2;
  101. if (r <= mid)
  102. return ranka(lch, l, r, x);
  103. if (l >= mid)
  104. return ranka(rch, l, r, x);
  105. return ranka(lch, l, mid, x) + ranka(rch, mid, r, x);
  106. }
  107. int val(int p, int l, int r, int rk)
  108. {
  109. int lo = -1e8, hi = 1e8 + 10;
  110. while (hi - lo > 1)
  111. {
  112. int mid = (lo + hi) / 2;
  113. if (ranka(0, l, r, mid) + 1 <= rk)//找排名<=rk的最大值
  114. lo = mid;
  115. else
  116. hi = mid;
  117. }
  118. return lo;
  119. }
  120. int pred(int p, int l, int r, int x)
  121. {
  122. int rk = ranka(0, l, r, x);
  123. if (rk < 1)
  124. return -2147483647;
  125. return val(0, l, r, rk);
  126. }
  127. int succ(int p, int l, int r, int x)
  128. {
  129. int rk = ranka(0, l, r, x + 1) + 1;
  130. if (rk > r - l)
  131. return 2147483647;
  132. return val(0, l, r, rk);
  133. }
  134. void solve()
  135. {
  136. builda(0, 1, N + 1);
  137. int opt, l, r, x, k, pos;
  138. for (int i = 1; i <= M; i++)
  139. {
  140. cin >> opt;
  141. switch (opt)
  142. {
  143. case 1:
  144. cin >> l >> r >> x;
  145. cout << ranka(0, l, r + 1, x) + 1 << endl;
  146. break;
  147. case 2:
  148. cin >> l >> r >> k;
  149. cout << val(0, l, r + 1, k) << endl;
  150. break;
  151. case 3:
  152. cin >> pos >> x;
  153. modifya(0, pos, x);
  154. A[pos] = x;
  155. break;
  156. case 4:
  157. cin >> l >> r >> x;
  158. cout << pred(0, l, r + 1, x) << endl;
  159. break;
  160. case 5:
  161. cin >> l >> r >> x;
  162. cout << succ(0, l, r + 1, x) << endl;
  163. break;
  164. }
  165. }
  166. }
  167. int main()
  168. {
  169. IOS;
  170. cin >> N >> M;
  171. for (int i = 1; i <= N; i++)
  172. cin >> A[i];
  173. solve();
  174. return 0;
  175. }
J.冰火战士

luoguP6619/LOJ3299
思路:
当温度确定时,消耗的总能量为冰火两方可参赛战士能量总和最少的一方

×

2

\times2

×2,于是我们只要求出这个最小值即可。
发现对于温度

K

K

K,可以参赛的冰系战士总能量是一个

K

K

K处的前缀和,而可以参赛的火系战士总能量是一个

K

K

K处的后缀和,可以发现冰系战士的总能量是随着温度增加而递增的,而火系是递减的,所以显然二者最小值在二者曲线交点处取最大,但由于二者的曲线不是连续的,所以最大值有两个可能的点,分别是最大的火系总能量

\geq

≥冰系的温度

k

1

k_{1}

k1​,以及最小的火系总能量

\leq

≤冰系的温度

k

2

k_{2}

k2​,这两个点的结果取最大值就是最多能量了,我们可以对温度离散化后用

B

I

T

BIT

BIT来维护冰,火两系战士的能量,而

k

1

,

k

2

k1,k2

k1,k2两个点可以通过在

B

I

T

BIT

BIT上二分来仅用一个

l

o

g

log

log的复杂度求得,

B

I

T

BIT

BIT上的二分可以理解为就是在上面做倍增,不过要注意维护一下已经跳过部分的贡献,冰系的很好维护,火系的由于需要的是后缀和,需要额外记录一下总和

F

I

R

E

FIRE

FIRE以及每个温度处的火系选手的能量值

F

[

i

]

F[i]

F[i],温度

T

T

T时火系选手的总温度就是

F

I

R

E

S

[

T

]

+

F

[

T

]

FIRE-S[T]+F[T]

FIRE−S[T]+F[T]。题目还要求在求得最大能量的前提下,温度要尽可能地大,显然如果答案取在

k

1

k_{1}

k1​,那么就已经是最大的了,而如果取在

k

2

k_{2}

k2​,答案为

x

x

x,我们可以再在

B

I

T

BIT

BIT上面二分来寻找火系总能量

x

\geq x

≥x的温度来作为答案即可。
复杂度

O

(

Q

l

o

g

N

)

O(QlogN)

O(QlogN)

代码:

  1. #include<bits/stdc++.h>
  2. #include<unordered_map>
  3. #include<unordered_set>
  4. using namespace std;
  5. typedef long long LL;
  6. typedef unsigned long long ULL;
  7. typedef pair<int, int> PII;
  8. //#define LL int
  9. #define endl '\n'
  10. #define inf 0x3f3f3f3f
  11. #define INF 0x3f3f3f3f3f3f3f3f
  12. #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  13. #pragma warning(disable :4996)
  14. const double eps = 1e-8;
  15. const LL mod = 1000000007;
  16. const LL MOD = 998244353;
  17. const int maxn = (1 << 21) + 5;
  18. int read()
  19. {
  20. int x = 0, f = 1;
  21. char c = getchar();
  22. while (c < '0' || c > '9')
  23. {
  24. if (c == '-')
  25. f = -1;
  26. c = getchar();
  27. }
  28. while (c >= '0' && c <= '9')
  29. {
  30. x = x * 10 + c - '0';
  31. c = getchar();
  32. }
  33. return x * f;
  34. }
  35. void write(int x)
  36. {
  37. if (x < 0)
  38. {
  39. putchar('-');
  40. x = -x;
  41. }
  42. if (x > 9)
  43. write(x / 10);
  44. putchar(x % 10 + '0');
  45. }
  46. int Q, M;
  47. int N[maxn], T[maxn], X[maxn], Y[maxn], K[maxn];
  48. int FIRE, F[(1 << 21) + 5];//fire总能量,各点上fire能量
  49. int S[(1 << 21) + 5];
  50. int dat[(1 << 21) + 5][2];//0:ice,1:fire
  51. int compress()
  52. {
  53. vector<int>xs;
  54. for (int i = 1; i <= Q; i++)
  55. {
  56. if (N[i] == 1)
  57. xs.push_back(X[i]);
  58. }
  59. sort(xs.begin(), xs.end());
  60. xs.erase(unique(xs.begin(), xs.end()), xs.end());
  61. for (int i = 1; i <= Q; i++)
  62. {
  63. if (N[i] == 1)
  64. {
  65. int tmp = X[i];
  66. X[i] = upper_bound(xs.begin(), xs.end(), X[i]) - xs.begin();
  67. S[X[i]] = tmp;
  68. }
  69. }
  70. return xs.size();
  71. }
  72. void add(int i, int x, int t)
  73. {
  74. while (i <= (1 << 21))
  75. {
  76. dat[i][t] += x;
  77. i += i & (-i);
  78. }
  79. }
  80. int sum(int i, int t)
  81. {
  82. int ans = 0;
  83. while (i > 0)
  84. {
  85. ans += dat[i][t];
  86. i -= i & (-i);
  87. }
  88. return ans;
  89. }
  90. PII query1()//(最右的fire>=ice点)
  91. {
  92. int k = 0, fire = FIRE, ice = 0;
  93. for (int i = 20; i >= 0; i--)
  94. {
  95. int t = k + (1 << i);
  96. if (fire - dat[t][1] + F[t] >= ice + dat[t][0])
  97. {
  98. fire -= dat[t][1];
  99. ice += dat[t][0];
  100. k = t;
  101. }
  102. }
  103. return PII(k, sum(k, 0));
  104. }
  105. PII query2()//(最左的fire<=ice点)
  106. {
  107. int k = 0, fire = FIRE, ice = 0;
  108. for (int i = 20; i >= 0; i--)
  109. {
  110. int t = k + (1 << i);
  111. if (fire - dat[t][1] + F[t] > ice + dat[t][0])
  112. {
  113. k = t;
  114. fire -= dat[t][1];
  115. ice += dat[t][0];
  116. }
  117. }
  118. return PII(k + 1, FIRE - sum(k + 1, 1) + F[k + 1]);
  119. }
  120. int query3(int x)//(最右的fire>=x点)
  121. {
  122. int k = 0, fire = FIRE;
  123. for (int i = 20; i >= 0; i--)
  124. {
  125. int t = k + (1 << i);
  126. if (fire - dat[t][1] + F[t] >= x)
  127. {
  128. k = t;
  129. fire -= dat[t][1];
  130. }
  131. }
  132. return k;
  133. }
  134. void solve()
  135. {
  136. M = compress();
  137. for (int i = 1; i <= Q; i++)
  138. {
  139. if (N[i] == 1)
  140. {
  141. add(X[i], Y[i], T[i]);
  142. if (T[i])
  143. {
  144. FIRE += Y[i];
  145. F[X[i]] += Y[i];
  146. }
  147. }
  148. else
  149. {
  150. int x = X[K[i]], y = Y[K[i]], t = T[K[i]];
  151. if (t)
  152. {
  153. FIRE -= y;
  154. F[x] -= y;
  155. }
  156. add(x, -y, t);
  157. }
  158. PII a = query1(), b = query2();
  159. int k1 = a.first, v1 = a.second;
  160. int k2 = b.first, v2 = b.second;
  161. int ans1, ans2;
  162. if (v1 > v2)
  163. ans2 = v1, ans1 = k1;
  164. else
  165. ans2 = v2, ans1 = k2;
  166. if (ans2 == v2)
  167. ans1 = query3(ans2);
  168. if (!ans2)
  169. puts("Peace");
  170. else
  171. {
  172. write(S[ans1]), putchar(' ');
  173. write(ans2 * 2), putchar('\n');
  174. }
  175. }
  176. }
  177. int main()
  178. {
  179. Q = read();
  180. for (int i = 1; i <= Q; i++)
  181. {
  182. N[i] = read();
  183. if (N[i] == 1)
  184. T[i] = read(), X[i] = read(), Y[i] = read();
  185. else
  186. K[i] = read();
  187. }
  188. solve();
  189. return 0;
  190. }
K.混合果汁

luoguP4602/LOJ2555
题目大意:

N

(

N

1

0

5

)

N(N\leq10^5)

N(N≤105)种果汁,每种果汁有美味度

d

i

d_{i}

di​,单价

p

i

p_{i}

pi​,购买上限

l

i

(

1

d

i

,

p

i

,

l

i

1

0

5

)

l_{i}(1\leq d_{i},p_{i},l_{i}\leq10^5)

li​(1≤di​,pi​,li​≤105),有

M

(

M

1

0

5

)

M(M\leq10^5)

M(M≤105)次询问,每次询问给出拥有的钱

g

i

g_{i}

gi​,至少购买的果汁升数

L

i

(

1

g

i

,

L

i

1

0

18

)

L_{i}(1\leq g_{i},L_{i}\leq10^{18})

Li​(1≤gi​,Li​≤1018),混合果汁的美味度为所购买的果汁中美味度最低的,对于每个询问,需要使所购买满足要求的混合果汁中美味度最大,如果不能购买满足要求的果汁,输出

1

-1

−1。

思路:
我们考虑单独

1

1

1个询问,显然我们可以二分美味度

d

d

d,

c

h

e

c

k

check

check时考虑所有

d

i

d

d_{i}\geq d

di​≥d的果汁,贪心地从单价低的开始购买,看能不能卖出满足要求的即可。
现在有多组询问,每次都直接二分显然是不行的,于是我们可以建一个主席树维护单价

p

p

p上的信息,对所有的

d

d

d从大到小可持久化(实现时对果汁按

d

d

d排序之后对下标可持久化,二分也改为二分下标即可),每个节点维护所辖区间的果汁总购买上限以及购买他们所需要的总价格,对于每个查询,二分

c

h

e

c

k

check

check时只需要查询主席树上对应的版本就可以了,这样每个询问可以在

O

(

l

o

g

2

N

)

O(log^2N)

O(log2N)的时间内回答,总的复杂度为

O

(

N

l

o

g

2

N

)

O(Nlog^2N)

O(Nlog2N)。

代码:

  1. #include<bits/stdc++.h>
  2. #include<unordered_map>
  3. #include<unordered_set>
  4. using namespace std;
  5. typedef long long LL;
  6. typedef unsigned long long ULL;
  7. typedef pair<int, int> PII;
  8. #define int LL
  9. #define endl '\n'
  10. #define inf 0x3f3f3f3f
  11. #define INF 0x3f3f3f3f3f3f3f3f
  12. #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  13. #pragma warning(disable :4996)
  14. const double eps = 1e-8;
  15. const LL mod = 1000000007;
  16. const LL MOD = 998244353;
  17. const int maxn = 100010;
  18. struct node {
  19. int lc, rc, sum, lim;
  20. }tr[maxn * 40];
  21. struct juice {
  22. int d, p, l;
  23. }J[maxn];
  24. int tot = 0, root[maxn], N, M, mx = -INF;
  25. bool cmp(const juice& a, const juice& b)
  26. {
  27. return a.d < b.d;
  28. }
  29. int build(int l, int r)//[)
  30. {
  31. int p = ++tot;
  32. if (l + 1 == r)
  33. {
  34. tr[p].lim = tr[p].sum = 0;
  35. return p;
  36. }
  37. int mid = (l + r) / 2;
  38. tr[p].lc = build(l, mid), tr[p].rc = build(mid, r);
  39. tr[p].lim = tr[tr[p].lc].lim + tr[tr[p].rc].lim;
  40. tr[p].sum = tr[tr[p].lc].sum + tr[tr[p].rc].sum;
  41. return p;
  42. }
  43. int modify(int now, int l, int r, int x, int val)
  44. {
  45. int p = ++tot;
  46. tr[p] = tr[now];
  47. if (l + 1 == r)
  48. {
  49. tr[p].sum += x * val, tr[p].lim += val;
  50. return p;
  51. }
  52. int mid = (l + r) / 2;
  53. if (x < mid)
  54. tr[p].lc = modify(tr[now].lc, l, mid, x, val);
  55. else
  56. tr[p].rc = modify(tr[now].rc, mid, r, x, val);
  57. tr[p].lim = tr[tr[p].lc].lim + tr[tr[p].rc].lim;
  58. tr[p].sum = tr[tr[p].lc].sum + tr[tr[p].rc].sum;
  59. return p;
  60. }
  61. bool query(int p, int q, int l, int r, int k, int s)//k:购买上限,s:所持有的钱数
  62. {
  63. if (k > tr[q].lim - tr[p].lim || s < 0)
  64. return false;
  65. if (l + 1 == r)
  66. return l * k <= s;
  67. int mid = (l + r) / 2;
  68. int llim = tr[tr[q].lc].lim - tr[tr[p].lc].lim, lsum = tr[tr[q].lc].sum - tr[tr[p].lc].sum;
  69. if (k <= llim)
  70. return query(tr[p].lc, tr[q].lc, l, mid, k, s);
  71. else
  72. return query(tr[p].rc, tr[q].rc, mid, r, k - llim, s - lsum);
  73. }
  74. void solve()
  75. {
  76. sort(J + 1, J + N + 1, cmp);
  77. int lst = J[N].d;
  78. root[0] = build(1, mx + 1);
  79. for (int i = N; i >= 1; i--)
  80. root[N - i + 1] = modify(root[N - i], 1, mx + 1, J[i].p, J[i].l);
  81. int g, l;
  82. for (int i = 1; i <= M; i++)
  83. {
  84. cin >> g >> l;
  85. int lo = 0, hi = N + 1;//对下标二分
  86. while (hi - lo > 1)
  87. {
  88. int mid = (hi + lo) / 2;
  89. if (query(root[0], root[N - mid + 1], 1, mx + 1, l, g))
  90. lo = mid;
  91. else
  92. hi = mid;
  93. }
  94. cout << (lo ? J[lo].d : -1) << endl;
  95. }
  96. }
  97. signed main()
  98. {
  99. IOS;
  100. cin >> N >> M;
  101. for (int i = 1; i <= N; i++)
  102. {
  103. cin >> J[i].d >> J[i].p >> J[i].l;
  104. mx = max(mx, J[i].p);
  105. }
  106. solve();
  107. return 0;
  108. }
L.陌上花开

luoguP3810/LOJ112
题目大意:

1

N

1

0

5

,

1

K

2

×

1

0

5

1\leq N\leq10^5,1\leq K\leq2\times10^5

1≤N≤105,1≤K≤2×105

思路:
三维偏序模板题,第一维排序,第二维用树状数组维护,第三维用动态开点的权值线段树维护。
(树状数组的每个节点维护一颗维护其所辖第二维区间上的第三维值域上面信息的线段树。)

代码:

  1. #include<bits/stdc++.h>
  2. #include<unordered_map>
  3. #include<unordered_set>
  4. using namespace std;
  5. typedef long long LL;
  6. typedef unsigned long long ULL;
  7. typedef pair<LL, int> PII;
  8. //#define int LL
  9. #define lch p*2+1
  10. #define rch p*2+2
  11. #define endl '\n'
  12. #define inf 0x3f3f3f3f
  13. #define INF 0x3f3f3f3f3f3f3f3f
  14. #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  15. #pragma warning(disable :4996)
  16. const double eps = 1e-8;
  17. const LL mod = 1000000007;
  18. const LL MOD = 998244353;
  19. const int maxn = 200010;
  20. const int SIZE = 30000000;
  21. int tot = 0;
  22. struct point {
  23. int a, b, c, id;
  24. bool operator<(const point& rhs)
  25. {
  26. if (a == rhs.a)
  27. {
  28. if (b == rhs.b)
  29. return c < rhs.c;
  30. return b < rhs.b;
  31. }
  32. return a < rhs.a;
  33. }
  34. bool operator==(const point& rhs)
  35. {
  36. return a == rhs.a && b == rhs.b && c == rhs.c;
  37. }
  38. };
  39. struct node {
  40. int dat, lc, rc;
  41. };
  42. node tr[SIZE];//内层权值线段树,动态开点
  43. int build()
  44. {
  45. ++tot;
  46. tr[tot].dat = tr[tot].lc = tr[tot].rc = 0;
  47. return tot;
  48. }
  49. void modify(int p, int l, int r, int val, int delta)
  50. {
  51. if (l + 1 == r)
  52. {
  53. tr[p].dat += delta;
  54. return;
  55. }
  56. int mid = (l + r) / 2;
  57. if (val < mid)
  58. {
  59. if (!tr[p].lc)
  60. tr[p].lc = build();
  61. modify(tr[p].lc, l, mid, val, delta);
  62. }
  63. else
  64. {
  65. if (!tr[p].rc)
  66. tr[p].rc = build();
  67. modify(tr[p].rc, mid, r, val, delta);
  68. }
  69. tr[p].dat = tr[tr[p].lc].dat + tr[tr[p].rc].dat;
  70. }
  71. int query(int p, int l, int r, int x)
  72. {
  73. if (p == 0 || l + 1 == r)
  74. return 0;
  75. int mid = (l + r) / 2;
  76. if (x >= mid)
  77. return tr[tr[p].lc].dat + query(tr[p].rc, mid, r, x);
  78. else
  79. return query(tr[p].lc, l, mid, x);
  80. }
  81. int N, K;
  82. int ans[maxn];
  83. point A[maxn];
  84. int dat[maxn], n;
  85. void add(int posx, int posy, int x)
  86. {
  87. while (posx <= n)
  88. {
  89. if (!dat[posx])
  90. dat[posx] = build();
  91. modify(dat[posx], 1, K + 5, posy, x);
  92. posx += posx & (-posx);
  93. }
  94. }
  95. int sum(int posx, int posy)
  96. {
  97. int tmp = 0;
  98. while (posx > 0)
  99. {
  100. tmp += query(dat[posx], 1, K + 5, posy + 1);
  101. posx -= posx & (-posx);
  102. }
  103. return tmp;
  104. }
  105. void solve()
  106. {
  107. n = K + 5;
  108. sort(A + 1, A + N + 1);
  109. int tmp = 1;
  110. for (int i = 1; i <= N; i++)
  111. {
  112. if (A[i] == A[i + 1])
  113. {
  114. tmp++;
  115. continue;
  116. }
  117. add(A[i].b, A[i].c, tmp);
  118. ans[sum(A[i].b, A[i].c) - 1] += tmp;
  119. tmp = 1;
  120. }
  121. for (int i = 0; i < N; i++)
  122. cout << ans[i] << endl;
  123. }
  124. int main()
  125. {
  126. IOS;
  127. cin >> N >> K;
  128. for (int i = 1; i <= N; i++)
  129. {
  130. cin >> A[i].a >> A[i].b >> A[i].c;
  131. A[i].id = i;
  132. }
  133. solve();
  134. return 0;
  135. }
M.A Plus B Problem

2021CCPC桂林站B
题目大意:
两个长度为

N

(

N

1

0

6

)

N(N\leq10^6)

N(N≤106)的数字

A

,

B

A,B

A,B做加法,结果也为一个长度为

N

N

N的数字(多出来的高位被忽略),

Q

(

Q

1

0

6

)

Q(Q\leq10^6)

Q(Q≤106)个次操作,每次操作把选择两个加数的其中一个,将其某一位数字替换为

0

0

0到

9

9

9中的一个数字,询问每次操作后,两个加数以及和中,总共有多少数字发生变化。

思路:
主要是要解决更改数字后的进位问题,对于每一位,最多向前进

1

1

1位,所以只要该位上两个加数的数字相加不等于

9

9

9,那么这一位向前进位与否就仅取决于自己,否则还要取决于更低一位是否进位,设当前位为

i

i

i,

i

i

i右边的第一个加数和不为

9

9

9的位记为

j

j

j,那么第

i

i

i位和数上的值就等于

(

A

i

+

B

i

+

[

A

j

+

B

j

10

]

)

%

10

(A_{i}+B_{i}+[A_{j}+B_{j}\geq 10])\%10

(Ai​+Bi​+[Aj​+Bj​≥10])%10
那么显然如果更改后某一位上的进位状态没有发生变化,就仅会改变

2

2

2个数字,如果发生了变化,那么受其原先进位状态影响的若干个连续的更高位也会发生变化,记

i

i

i位左侧首个加数和不为

9

9

9的位为

j

j

j,

i

i

i位所能影响的就是

j

j

j到

i

i

i这若干位,于是变化的位数就是这些位数

+

1

+1

+1了。
我们可以维护所有加数和不等于

9

9

9的位,并且要插入,删除,查询前驱后继,所以我们用

s

e

t

set

set就可以轻松维护,在

O

(

Q

l

o

g

N

)

O(QlogN)

O(QlogN)内解决问题。
注意一些边界情况要特别处理一下。

代码:

  1. #include<bits/stdc++.h>
  2. #include<unordered_map>
  3. #include<unordered_set>
  4. using namespace std;
  5. typedef long long LL;
  6. typedef unsigned long long ULL;
  7. typedef pair<int, int> PII;
  8. //#define int LL
  9. #define endl '\n'
  10. #define inf 0x3f3f3f3f
  11. #define INF 0x3f3f3f3f3f3f3f3f
  12. #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  13. #pragma warning(disable :4996)
  14. const double eps = 1e-8;
  15. const LL mod = 1000000007;
  16. const LL MOD = 998244353;
  17. const int maxn = 1000010;
  18. int N, Q;
  19. string S[2];
  20. int num[2][maxn];
  21. set<int>ss;
  22. void solve()
  23. {
  24. ss.insert(N + 1), ss.insert(0);
  25. for (int i = 1; i <= N; i++)
  26. {
  27. num[0][i] = S[0][i - 1] - '0', num[1][i] = S[1][i - 1] - '0';
  28. if (num[0][i] + num[1][i] != 9)
  29. ss.insert(i);
  30. }
  31. int r, c, d;
  32. for (int i = 1; i <= Q; i++)
  33. {
  34. int ans1 = 2, ans2;
  35. cin >> r >> c >> d;
  36. bool up1 = false, up2 = false;
  37. int up = 0;
  38. int a = num[1][c] + num[0][c];
  39. int succ = *ss.upper_bound(c);
  40. up = num[1][succ] + num[0][succ] >= 10;
  41. if (a + up >= 10)
  42. up1 = true;
  43. if (a != 9)
  44. ss.erase(c);
  45. num[r - 1][c] = d;
  46. int b = num[1][c] + num[0][c];
  47. if (b != 9)
  48. ss.insert(c);
  49. succ = *ss.upper_bound(c);
  50. up = num[1][succ] + num[0][succ] >= 10;
  51. if (b + up >= 10)
  52. up2 = true;
  53. ans2 = (b + up) % 10;
  54. if (a == b)
  55. {
  56. cout << ans2 << ' ' << 0 << endl;
  57. continue;
  58. }
  59. if (up1 ^ up2)
  60. {
  61. int pred = *(--ss.lower_bound(c));
  62. ans1 += c - pred;
  63. if (pred == 0)
  64. ans1--;
  65. }
  66. cout << ans2 << ' ' << ans1 << endl;
  67. }
  68. }
  69. int main()
  70. {
  71. IOS;
  72. cin >> N >> Q >> S[0] >> S[1];
  73. solve();
  74. return 0;
  75. }

AHUACM寒假集训II(线段树)的更多相关文章

  1. UVA10869 - Brownie Points II(线段树)

    UVA10869 - Brownie Points II(线段树) 题目链接 题目大意:平面上有n个点,Stan和Ollie在玩游戏,游戏规则是:Stan先画一条竖直的线作为y轴,条件是必需要经过这个 ...

  2. 2020牛客寒假算法基础集训营3 - G. 牛牛的Link Power II(线段树)

    题目链接:牛牛的Link Power II 题意:给你一个只含$0$和$1$的串,定义串的$Link$值为串中两个的$1$之间的距离的和,$(u,v)$和$(v,u)$被看认为是同一对,有$m$次操作 ...

  3. CDOJ 1259 昊昊爱运动 II 线段树+bitset

    昊昊爱运动 II 昊昊喜欢运动 他N天内会参加M种运动(每种运动用一个[1,m]的整数表示) 现在有Q个操作,操作描述如下 昊昊把第l天到第r天的运动全部换成了x(x∈[1,m]) 问昊昊第l天到第r ...

  4. SPOJ 1557. Can you answer these queries II 线段树

    Can you answer these queries II Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://www.spoj.com/pr ...

  5. bzoj 2482: [Spoj GSS2] Can you answer these queries II 线段树

    2482: [Spoj1557] Can you answer these queries II Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 145 ...

  6. 4990: [Usaco2017 Feb]Why Did the Cow Cross the Road II 线段树维护dp

    题目 4990: [Usaco2017 Feb]Why Did the Cow Cross the Road II 链接 http://www.lydsy.com/JudgeOnline/proble ...

  7. hdu 5831 Rikka with Parenthesis II 线段树

    Rikka with Parenthesis II 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5831 Description As we kno ...

  8. 【CF687D】Dividing Kingdom II 线段树+并查集

    [CF687D]Dividing Kingdom II 题意:给你一张n个点m条边的无向图,边有边权$w_i$.有q个询问,每次给出l r,问你:如果只保留编号在[l,r]中的边,你需要将所有点分成两 ...

  9. 【BZOJ2482】[Spoj1557] Can you answer these queries II 线段树

    [BZOJ2482][Spoj1557] Can you answer these queries II Description 给定n个元素的序列. 给出m个询问:求l[i]~r[i]的最大子段和( ...

随机推荐

  1. 布客&#183;ApacheCN 编程/后端/大数据/人工智能学习资源 2020.9

    公告 ApacheCN 项目的最终目标:五年内备份并翻译 Github 上的所有教程(其实快被我们啃完了,剩下的不多了). 警告各位培训班:对 ApacheCN 宣传文章的举报,也将视为对 Apach ...

  2. 社交网络分析的 R 基础:(三)向量、矩阵与列表

    在第二章介绍了 R 语言中的基本数据类型,本章会将其组装起来,构成特殊的数据结构,即向量.矩阵与列表.这些数据结构在社交网络分析中极其重要,本质上对图的分析,就是对邻接矩阵的分析,而矩阵又是由若干个向 ...

  3. NoSuchMethodError错误

    发生原因: 一个项目中包含有相同名字,但内容不同的包 解决办法:删除其中暂时不用的包 后记:如果不知道哪一个包是多余的,直接用IDE查找:找到该类,然后将该包进行反编译,再次导入该项目,再找到该类,出 ...

  4. bom-client

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. CentOS 7中的系统语言包及UTF-8、en_US.UTF-8和zh_CN.UTF-8的区别

    UTF-8.en_US.UTF-8和zh_CN.UTF-8的区别 en_US.UTF-8.zh_CN.UTF-8叫做字符集,就是说'A'.'B'.'中'.'国'等对应的整数值,en_US.UTF-8只 ...

  6. Java8-Consumer、Supplier、Predicate和Function方法总结

    这几个接口都在 java.util.function 包下的,分别是Consumer(消费型).supplier(供给型).predicate(谓词型).function(功能性): 那么,下面,我们 ...

  7. 动态修改UINavigationBar的背景色--by-胡旭

    这是我们最终想要得到的效果 思路 在UISrollView的delegate方法 - (void)scrollViewDidScroll:(UIScrollView *)scrollView中根据当前 ...

  8. LeetCode随缘刷题之字符串转换整数

    package leetcode.day_01_29; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 请你 ...

  9. Typora如何上传图片到gitee

    Typora是一款非常好用的Markdown文本编辑器,深受广大程序员的青睐,那么在使用过程中,当我们插入图片的时候,其实是默认放在一个相对路径文件夹下的,这就导致,一旦我们移动文件,或者发送给别人, ...

  10. CentOS卸载自带的JDK

    一般在配置JDK之前要卸载CentOS自带的openjdk,接下来演示如何卸载自带的openjdk 进入root模式 查看jdk是否已经安装jdk rpm -qa | grep jdk 3. 卸载op ...