There are two sequences a1, a2, · · · , an, b1, b2, · · · , bn. Let S(t) = ∑n
i=1⌊
t−bi
ai
⌋. There are m operations
within three kinds as following:
• 1 x y: change value ax to y.
• 2 x y: change value bx to y.
• 3 k: ask min{t|k ≤ S(t)}
Input
The first line contains a integer T (1 ≤ T ≤ 5) representing the number of test cases.
For each test case, the first line contains two integers n (1 ≤ n ≤ 100000), m (1 ≤ m ≤ 10000).
The following line contains n integers representing the sequence a1, a2, · · · , an.
The following line contains n integers representing the sequence b1, b2, · · · , bn.
The following m lines, each line contains two or three integers representing an operation mentioned
above.
It is guaranteed that, at any time, we have 1 ≤ ai ≤ 1000, 1 ≤ bi
, k ≤ 109
. And the number of
queries (type 3 operation) in each test case will not exceed 1000.
Output
For each query operation (type 3 operation), print the answer in one line.
训练赛的时候想到了用二分答案做,但是一直没有优化的想法,这次也算是接触了一次全新的优化思想吧…
首先我们为了优化S(t)函数,需要将t和
b
i
b_i
bi从向下取整的式子中取出来。
这里可以令
t
=
k
1
i
∗
a
i
+
c
1
i
,
b
i
=
k
2
i
∗
a
i
+
c
2
i
t=k_{1i}*a_i+c_{1i},b_i=k_{2i}*a_i+c_{2i}
t=k1i∗ai+c1i,bi=k2i∗ai+c2i,这样我们便可以将S(t)函数优化成
S ( t ) = K 1 − K 2 + ∑ i = 1 n ⌊ c 1 i − c 2 i a i ⌋ S(t)=K1-K2+\sum_{i=1}^{n}\lfloor\frac{c_{1i}-c_{2i}}{a_i}\rfloor S(t)=K1−K2+∑i=1n⌊aic1i−c2i⌋
其中
K
1
=
∑
i
=
1
n
k
1
i
=
∑
i
=
1
n
⌊
t
a
i
⌋
K1 = \sum_{i=1}^{n}k_{1i}=\sum_{i=1}^{n}\lfloor\frac{t}{a_i}\rfloor
K1=∑i=1nk1i=∑i=1n⌊ait⌋
K
2
=
∑
i
=
1
n
k
2
i
=
∑
i
=
1
n
⌊
b
i
a
i
⌋
K2 = \sum_{i=1}^{n}k_{2i}=\sum_{i=1}^{n}\lfloor\frac{b_i}{a_i}\rfloor
K2=∑i=1nk2i=∑i=1n⌊aibi⌋
K1的计算可以通过对 a i a_i ai进行预处理来完成,因为 a i ≤ 1000 a_i\le1000 ai≤1000,那么只要用一个数组记录 a a a中每个数字的出现次数,就可以通过 ∑ i = 1 1000 t / i ∗ c n t [ i ] \sum_{i=1}^{1000}t/i*cnt[i] ∑i=11000t/i∗cnt[i]便可以计算K1了。
K2可以在输入的时候进行预处理,再进行操作1、2时,通过 K 2 = K 2 − ⌊ b i a i ⌋ + ⌊ b i y ⌋ K2=K2-\lfloor\frac{b_i}{a_i}\rfloor+\lfloor\frac{b_i}{y}\rfloor K2=K2−⌊aibi⌋+⌊ybi⌋和 K 2 = K 2 − ⌊ b i a i ⌋ + ⌊ y a i ⌋ K2=K2-\lfloor\frac{b_i}{a_i}\rfloor+\lfloor\frac{y}{a_i}\rfloor K2=K2−⌊aibi⌋+⌊aiy⌋进行复杂度为O(1)的更新。
最后是 ∑ i = 1 n ⌊ c 1 i − c 2 i a i ⌋ \sum_{i=1}^{n}\lfloor\frac{c_{1i}-c_{2i}}{a_i}\rfloor ∑i=1n⌊aic1i−c2i⌋,我们知道 c 1 i , c 2 i < a i c_{1i},c_{2i}<a_i c1i,c2i<ai,则
⌊
c
1
i
−
c
2
i
a
i
⌋
=
0
\lfloor\frac{c_{1i}-c_{2i}}{a_i}\rfloor=0
⌊aic1i−c2i⌋=0
c
1
i
≥
c
2
i
c_{1i}\ge c_{2i}
c1i≥c2i
⌊
c
1
i
−
c
2
i
a
i
⌋
=
−
1
\lfloor\frac{c_{1i}-c_{2i}}{a_i}\rfloor=-1
⌊aic1i−c2i⌋=−1
c
1
i
<
c
2
i
c_{1i}< c_{2i}
c1i<c2i
所以我们需要对 c 1 i < c 2 i c_{1i}<c_{2i} c1i<c2i的情况进行讨论,也就是 t % a i < b i % a i t\%a_i<b_i\%a_i t%ai<bi%ai的情况。这里可以使用一个二维数组,arr[x][y]表示满足 a i = x a_i=x ai=x且 b i % a i ≥ y b_i\%a_i\ge y bi%ai≥y的个数,同时K1的计算也可以通过arr[x][0]来获得a数组中等于x的数量。所以最后一部分的值为 ∑ i = 1 1000 a r r [ i ] [ t % i + 1 ] \sum_{i=1}^{1000}arr[i][t\%i+1] ∑i=11000arr[i][t%i+1]。
在可以快速求出S(t)后,从1到1e13求一遍二分答案即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int t,n,m,x,y,k,op;
int a[N],b[N],book[1005][1005];
long long K1,K2;
bool judge(long long mid){
long long res = 0;
for(int i = 1;i<=1000;i++){ //求出每个t值对应的S(t)函数值,并判断是否符合条件
res += mid/i*book[i][0];
res -= book[i][mid%i+1];
}
return k<=res-K2;
}
int main() {
ios::sync_with_stdio(false);
cin>>t;
while(t--){
cin>>n>>m;
K2 = 0;
memset(book,0,sizeof(book));
for(int i = 1;i<=n;i++){
cin>>a[i];
}
for(int i = 1;i<=n;i++){
cin>>b[i];
K2 += b[i]/a[i];
book[a[i]][b[i]%a[i]]++; //预处理
}
for(int i = 1;i<=1000;i++){
for(int j = i-1;j>=0;j--){
book[i][j] += book[i][j+1];
}
}
while(m--){
cin>>op;
if(op==1){
cin>>x>>y;
for(int i = b[x]%a[x];i>=0;i--){
book[a[x]][i]--;
}
for(int i = b[x]%y;i>=0;i--){
book[y][i]++;
}
K2 -= (b[x]/a[x]);
K2 += (b[x]/y);
a[x] = y;
}else if(op==2){
cin>>x>>y;
for(int i = b[x]%a[x];i>=0;i--){
book[a[x]][i]--;
}
for(int i = y%a[x];i>=0;i--){
book[a[x]][i]++;
}
K2 -= (b[x]/a[x]);
K2 += (y/a[x]);
b[x] = y;
}else{
cin>>k;
long long l = 1,r = 1e13,res = 0;
while(l<=r){ //二分答案
long long mid = (l+r)/2;
if(judge(mid)){
res = mid;
r = mid-1;
}else{
l = mid+1;
}
}
cout<<res<<'\n';
}
}
}
return 0;
}