HDU - 6274 Master of Sequence

There are two sequences a1, a2, · · · , an, b1, b2, · · · , bn. Let S(t) =∑⌊(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.

思路:我们发现,(t-b[i])/a[i],我们可以拆开,拆成t/a[i]-b[i]/a[i],然后t/a[i]和b[i]/a[i]也对应相减,因为是下取整,所以这样如果模数相减小于0,结果-1,否则不变.
而且发现a[i]最大为1000,这样我们可以做个桶把所有b[i]都存到对应的a[i]处,这样我们计算
t/a[i]-b[i]/a[i]就特别好算,我们怎么知道每一项模数相减是不是小于0呢,也就是怎么知道对应
a[i]∈[1,1000],t取每个值我们怎么知道有多少个b[i]%a[i]> t%a[i]呢? 树状数组不就可以了嘛!
维护1000个树状数组即可,这样每次查询的复杂度就是1000*log1000.

当然也可以预处理每个模数出现次数的前缀和,查询有多少模数比t%a[i]大时的复杂度就是O(1),
修改就是O(N),看起来好像不如树状数组,但是对于这道题目跑起来确实是快.
代码:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5+5;

int n,m;
ll b[maxn],sumb[1234],a[maxn],num[1234];
int c[1234][1234];

int lowbit(int x)
{
	return x&(-x);
}

void add(int pos,int x,int val)
{
	x++;
	for(int i = x;i<= 1000;i+= lowbit(i))
		c[pos][i]+= val;
	return ;
}

int get_sum(int pos,int x)
{
	x++;
	int ans = 0;
	for(int i = 1000;i> 0;i-= lowbit(i))
		ans+= c[pos][i];
	for(int i = x;i> 0;i-= lowbit(i))
		ans-= c[pos][i];
	return ans;
}

bool judge(ll t,ll sum)
{
	ll all = 0;
	for(int i = 1;i<= 1000;i++)
	{
		all+= t/i*num[i]-sumb[i];
		all-= get_sum(i,t%i);
	}
	
	return all>= sum;
}

void solve(ll sum)
{
	ll l = 1,r = 1e14;
	while(l<= r)
	{
		ll mid = (l+r)>>1;
		if(judge(mid,sum))
			r = mid-1;
		else
			l = mid+1;
	}
	
	printf("%lld\n",l);
}

int main()
{
	int t;
	cin>>t;
	
	while(t--)
	{
		mem(sumb,0);
		mem(num,0);
		mem(c,0);
		scanf("%d %d",&n,&m);
		for(int i = 1;i<= n;i++)
			scanf("%lld",&a[i]);
		for(int i = 1;i<= n;i++)
		{
			scanf("%lld",&b[i]);
			sumb[a[i]]+= b[i]/a[i];
			add(a[i],b[i]%a[i],1);
			num[a[i]]++;
		}
		
		while(m--)
		{
			ll o,x,y;
			scanf("%lld %lld",&o,&x);
			if(o == 1)
			{
				scanf("%lld",&y);
				sumb[a[x]]-= b[x]/a[x];
				add(a[x],b[x]%a[x],-1);
				num[a[x]]--;
				a[x] = y;
				sumb[a[x]]+= b[x]/a[x];
				add(a[x],b[x]%a[x],1);
				num[a[x]]++;
			}
			else if(o == 2)
			{
				scanf("%lld",&y);
				sumb[a[x]]-= b[x]/a[x];
				add(a[x],b[x]%a[x],-1);
				b[x] = y;
				sumb[a[x]]+= b[x]/a[x];
				add(a[x],b[x]%a[x],1);
			}
			else
			{
				solve(x);
			}
		}
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值