HDU 6274 Master of sequence(二分答案 + 树状数组)

版权声明:本文为博主原创文章,转载请著名出处 http://blog.csdn.net/u013534123 https://blog.csdn.net/u013534123/article/details/82284542

大致题意:给你两个数列{ai}和{bi}。每次有三种操作,对于第一种是改变某个ai,第二种是改变某个bi,第三种是让你求满足S(t)=\sum_{i=1}^{n}\lfloor\frac{t-b_i}{a_i}\rfloor\ >\ k的最小的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;
}

猜你喜欢

转载自blog.csdn.net/u013534123/article/details/82284542