ZOJ-4082:Little Sub and his Geometry Problem(二分+BIT)

本文介绍了一种使用树状数组和二分搜索优化的算法,用于解决特定类型的查询问题。通过预处理点坐标并利用树状数组记录点的个数及坐标和,实现快速计算函数F(u,v),并通过二分搜索找到满足条件的点v。文章提供了完整的代码实现,并指出在特定条件下无解的情况,避免了不必要的计算。

题目链接

思路:对于每个询问来说,每一个 u u u,只存在一个 v v v使得 F ( u , v ) = C i F(u,v)=C_i F(u,v)=Ci
那么提前将点按 x x x坐标排好序,枚举 u u u,将 x ≤ u x\le u xu的点放入BIT,用树状数组记录点的个数及 x + y x+y x+y的值,然后二分 v v v
二分时用树状数组计算 F ( u , v ) F(u,v) F(u,v)
PS:当 C i > 2 ∗ 1 0 10 C_i>2*10^{10} Ci>21010时,显然无解;没优化这个之前,一直TLE。。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
const int MOD=1e9+7;
const int INF=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
struct Point{int x,y;}p[MAX];
int cmp(const Point&A,const Point &B){return A.x<B.x;}
ll A[MAX],B[MAX];
ll C[11],ans[11];
int n,m;
void add(int x,int y)
{
    while(x<=n)
    {
        A[x]++;
        B[x]+=y;
        x+=x&(-x);
    }
}
ll cal(int x,int y)
{
    ll ans=0,cnt=0;
    int Q=y;
    while(Q){cnt+=A[Q];ans+=B[Q];Q-=Q&(-Q);}
    return cnt*(x+y)-ans;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)scanf("%d%d",&p[i].x,&p[i].y);
        sort(p+1,p+m+1,cmp);
        int QWQ;
        scanf("%d",&QWQ);
        for(int i=1;i<=QWQ;i++)scanf("%lld",&C[i]);
        memset(ans,0,sizeof ans);
        int R=1;
        for(int i=1;i<=n;i++)A[i]=B[i]=0;
        for(int x=1;x<=n;x++)
        {
            while(R<=m&&p[R].x<=x)
            {
                add(p[R].y,p[R].y+p[R].x);
                R++;
            }
            for(int i=1;i<=QWQ;i++)
            {
                if(C[i]>=2e10)continue;
                int l=1,r=n;
                if(cal(x,n)<C[i])continue;
                if(cal(x,1)>C[i])continue;
                while(r>=l)
                {
                    int mid=(l+r)/2;
                    ll Back=cal(x,mid);
                    if(Back>C[i])r=mid-1;
                    else if(Back==C[i])
                    {
                        ans[i]++;
                        break;
                    }
                    else l=mid+1;
                }
            }
        }
        for(int i=1;i<=QWQ;i++)printf("%lld%c",ans[i],i==QWQ?'\n':' ');
    }
    return 0;
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值