题目大意:
• 1 x y: 将ax改成y
• 2 x y: 将bx改成y
• 3 k: ask min{t|k≤S(t)}
题目思路:设t=k1*ai+c1,bi=k2*ai+c2,原式变为(k1*ai+c1-(k2*ai+c2))/a[i]的向下取整。c1>=c2时,由于其范围都在0~ai-1内,所以c1-c2还是在0~ai-1内,对答案不产生影响,若c1<c2,那么就需要原答案-1,那么就开一个num[x][y]数组,表示当a为x时,b%a>=y的情况数。接着二分t,由于可以移项,所以等价于check函数得到的值大于等于查询的值+k2的和,x/i得到k1,一共有num[i][0]个a[i]的数,那就说明有k1求出c2>=c1,c1用x%a得出。由于查询和修改涉及0,树状数组修改的点的位置需要+1。对于修改,每次都去掉之前的影响,换成新的影响即可。
以下是代码:
数组版本:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
#define PI acos(-1)
const ll MAXN = 1e5+5;
ll a[MAXN],b[MAXN];
ll num[1005][1005];
ll temp;
bool check(ll x){
ll rst=0;
rep(i,1,1000){
rst+=x/i*num[i][0];
rst-=num[i][x%i+1];
}
if(rst>=temp)return true;
return false;
}
int main()
{
ll t,n,m,z,x,y;
scanf("%lld",&t);
while(t--){
memset(num,0,sizeof(num));
scanf("%lld%lld",&n,&m);
ll rst=0;
rep(i,1,n)scanf("%lld",&a[i]);
rep(i,1,n)scanf("%lld",&b[i]),rst+=b[i]/a[i],num[a[i]][b[i]%a[i]]++;
rep(i,1,1000){
per(j,i-1,0){
num[i][j]+=num[i][j+1];
}
}
while(m--){
scanf("%lld",&z);
if(z==1){
scanf("%lld%lld",&x,&y);
rst-=b[x]/a[x];
per(i,b[x]%a[x],0)num[a[x]][i]--;
rep(i,0,b[x]%y)num[y][i]++;
a[x]=y;
rst+=b[x]/y;
}
else if(z==2){
scanf("%lld%lld",&x,&y);
rst-=b[x]/a[x];
per(i,b[x]%a[x],0)num[a[x]][i]--;
rep(i,0,y%a[x])num[a[x]][i]++;
b[x]=y;
rst+=y/a[x];
}
else{
scanf("%lld",&x);
temp=rst+x;
ll l=1,r=1e13,ans=-1;
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid)){
r=mid-1;
ans=mid;
}
else{
l=mid+1;
}
}
printf("%lld\n",ans);
}
}
}
return 0;
}
树状数组版本:
include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
#define PI acos(-1)
const ll MAXN = 1e5+5;
ll a[MAXN],b[MAXN];
ll num[1005][1005];
ll temp;
void add(ll p,ll x,ll y){x++;
for(;x;x-=x&-x)num[p][x]+=y;
}
ll query(ll p,ll x){x++;
ll ans=0;
for(;x<1005;x+=x&-x)ans+=num[p][x];
return ans;
}
bool check(ll x){
ll rst=0;
rep(i,1,1000){
rst+=x/i*query(i,0);
rst-=query(i,x%i+1);
}
if(rst>=temp)return true;
return false;
}
int main()
{
ll t,n,m,z,x,y;
scanf("%lld",&t);
while(t--){
memset(num,0,sizeof(num));
scanf("%lld%lld",&n,&m);
ll rst=0;
rep(i,1,n)scanf("%lld",&a[i]);
rep(i,1,n)scanf("%lld",&b[i]),rst+=b[i]/a[i],add(a[i],b[i]%a[i],1);
while(m--){
scanf("%lld",&z);
if(z==1){
scanf("%lld%lld",&x,&y);
rst-=b[x]/a[x];
add(a[x],b[x]%a[x],-1);
add(y,b[x]%y,1);
a[x]=y;
rst+=b[x]/y;
}
else if(z==2){
scanf("%lld%lld",&x,&y);
rst-=b[x]/a[x];
add(a[x],b[x]%a[x],-1);
add(a[x],y%a[x],1);
b[x]=y;
rst+=y/a[x];
}
else{
scanf("%lld",&x);
temp=rst+x;
ll l=1,r=1e13,ans=-1;
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid)){
r=mid-1;
ans=mid;
}
else{
l=mid+1;
}
}
printf("%lld\n",ans);
}
}
}
return 0;
}