2019 Multi-University Training Contest 3 Find the answer (离散化+二分+树状数组)
Posted zjl192628928
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019 Multi-University Training Contest 3 Find the answer (离散化+二分+树状数组)相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6609
题目大意:给定一个含有n个数的序列,还有一个m,对于每个i(1<=i<=n)求出最少需要将前i-1个数中的多少个数改成0,才能使得前i个数的和小于m
解题思路:很容易想到,我们应该将比较大的数变为0,答案才是最优的。所以我们直接给他们排个序离散化一下,对应它们在树上的编号,树上节点存两个东西,一个是节点的权值之和,还有一个就是包含数的个数,每次查询时,先将前i-1个数更新到树上,可以保证后面的数不影响答案,假设前i个数的和sum-m=x,则我们只要二分找到个一个最大的l,使得区间[l,n]大于等于x就可以了,这样答案就是区间[l,n]的数的个数了。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+7; int n,m,ans[maxn]; struct node int val,id,rk; a[maxn]; bool cmp1(node x,node y) return x.val<y.val; bool cmp2(node x,node y) return x.id<y.id; ll sum[maxn],num[maxn]; int Ans; int lowbit(int x) return x&(-x); void add(int x,ll val) while(x<=n) num[x]++; sum[x]+=val; x+=lowbit(x); ll ask(int x) ll res=0; while(x) Ans+=num[x]; res+=sum[x]; x-=lowbit(x); return res; int main() int t; scanf("%d",&t); while(t--) memset(num,0,sizeof(num)); memset(sum,0,sizeof(sum)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i].val); a[i].id=i; sort(a+1,a+1+n,cmp1); for(int i=1;i<=n;i++) a[i].rk=i; sort(a+1,a+1+n,cmp2); ll tmp=0; for(int i=1;i<=n;i++) tmp+=a[i].val; if(tmp<=m)ans[i]=0; else ll x=tmp-m; int l=0,r=n; Ans=0; ll s1=ask(n); ll Ans1=Ans; while(l<=r) int mid=l+r>>1; Ans=0; ll s2=ask(mid); ll Ans2=Ans; if(s1-s2>=x) ans[i]=Ans1-Ans2; l=mid+1; else r=mid-1; // cout<<a[i].rk<<" "<<a[i].val<<endl; add(a[i].rk,a[i].val); for(int i=1;i<=n;i++) printf("%d ",ans[i]); printf("\n"); return 0;
以上是关于2019 Multi-University Training Contest 3 Find the answer (离散化+二分+树状数组)的主要内容,如果未能解决你的问题,请参考以下文章
2019 Multi-University Training Contest 6
2019 Multi-University Training Contest 6
2019 Multi-University Training Contest 6
2019 Multi-University Training Contest 3