大致题意:给你两个数列{ai}和{bi}。每次有三种操作,对于第一种是改变某个ai,第二种是改变某个bi,第三种是让你求满足的最小的t。
首先,这种求满足条件的最小值,肯定是二分答案无疑了。然后我们看这个S(t)的表达式子,一个很显然的想法是把分子拆分成为两个部分,一个是bi/ai和t/ai,另一个是bi%ai和t%ai。然后相减也是两部分相减,可以看出,最后的结果就是前一部分之差,然后后面一部分如果之差大于等于0,那么结果不变,否则还要再减去一个1。
然后,本题看到了一个特殊的条件,ai的范围只会到1000,而且操作3的个数也只有1000,所以我们可以在这个1000上做文章了。我们可以按照这个1000来对分母进行分类,维护每一对(ai,bi)的整数部分,求个和记为s。对于一个操作3的询问k,首先减去这个s,然后在看分数部分的大小关系。我们枚举每一个分母,t的整数部分就是t/ai*tt[ai],tt[ai]表示ai这个分母的出现次数。接着,看这个分母下,分数部分大于t%ai的个数有多少个。减去每一个分母下大于t%ai的个数即可。这个我们可以维护1000个树状数组,每个树状数组对应一个分母,每个c[i]记录分母下分数部分小于i的数字个数。这样就可以在O(logN)的复杂度内知道大于t%ai的个数。
于是,对于操作1和操作2,我们维护s和对应的树状数组,对于操作3我们首先用k减去s,然后二分最后的答案t,遍历每一个分母,看看计算每一个分母下t的整数部分,然后对于分数部分看有多少个大于t%ai的,减去即可。最后再比较两个大小就可以知道当前答案是否合法。总的时间复杂度O(1000*1000*logt*log1000)对于10s的时间,完全没有问题。具体见代码:
#include<bits/stdc++.h>
#define LL long long
#define mod 998244353
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define INF 0x3f3f3f3f
#define sf(x) scanf("%d",&x)
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#define sc(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define clr(x,n) memset(x,0,sizeof(x[0])*(n+5))
#define file(x) freopen(#x".out","w",stdout)
using namespace __gnu_pbds;
using namespace std;
const int N = 1e3 + 10;
const int M = 1e5 + 10;
int a[M],b[M],t[M];
struct BinaryIndexTree
{
int c[N];
inline void update(int x,int y)
{
x++;
for(int i=x;i<N;i+=i&-i)
c[i]+=y;
}
inline int getsum(int x)
{
int res=0; x++;
for(int i=x;i;i-=i&-i)
res+=c[i];
return res;
}
} BIT[N];
inline bool check(LL x,LL y)
{
LL s=0;
for(int i=1;i<=1000;i++)
{
s+=(x/i)*t[i]-(t[i]-BIT[i].getsum(x%i));
if (s>=y+1000-i) return 1;
}
return s>=y;
}
int main()
{
int T;sf(T);
while(T--)
{
int n,m;LL s=0;
sf(n); sf(m);
memset(t,0,sizeof(t));
memset(BIT,0,sizeof(BIT));
for(int i=1;i<=n;i++)
{
sf(a[i]); t[a[i]]++;
}
for(int i=1;i<=n;i++)
{
sf(b[i]); s+=b[i]/a[i];
BIT[a[i]].update(b[i]%a[i],1);
}
while(m--)
{
LL ans;
int op,x,y;
sf(op);
if (op==1)
{
sf(x); sf(y);
s=s-b[x]/a[x]+b[x]/y; t[a[x]]--;
BIT[a[x]].update(b[x]%a[x],-1);
BIT[y].update(b[x]%y,1); a[x]=y; t[y]++;
}
if (op==2)
{
sf(x); sf(y);
s=s-b[x]/a[x]+y/a[x];
BIT[a[x]].update(b[x]%a[x],-1);
BIT[a[x]].update(y%a[x],1); b[x]=y;
}
if (op==3)
{
sf(x); LL xx=x+s;
LL l=0,r=2e12,mid;
while(l<=r)
{
mid=(l+r)>>1;
if (check(mid,xx)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%lld\n",ans);
}
}
}
return 0;
}