zoj月赛 B题 Little Sub and his Geometry Problem zoj4082

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4082

题意:题目给k个点(x,y),所有点1<=x<=n,1<=y<=n,然后q次询问,一个点p的权值为所有在p左下方的点到p的曼哈顿距离(x差值和y差值的和)和,一共q次询问,每次给一个常数c,求点P个数,P(x,y)满足1<=x<=n,1<=y<=n,且到给出的k个点距离和的值等于c的点的个数。

思路:一开始一直想着用线段树维护,然后发现很复杂......然后自闭,看了题解之后发现确实可以用可持续化线段树,但是可以巧解,于是果断选择巧解...可持续化线段树写不来的......按x(或者按y都一样)遍历坐标,维护该横坐标上所有y坐标对应的左侧点个数cnt[y]和对应横纵坐标和sum[y],然后放一个res从n开始往下扫,如果满足cnt*(x+y)-sum=c,那就找到了,然后横坐标往右扫,每个横坐标上最多一个满足情况的值,如果大于c就把res往下,小于c就横坐标往后扫

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll mod = 1000000007;
const int maxn = 1e5 + 50;
#define INF 0xffffff


typedef struct node
{
    int x, y;
}node;

int n , k, q;
ll c[15];
node p[maxn];
int cnt[maxn];
ll sum[maxn];

bool cmp(node a, node b)
{
    if(a.x==b.x)
        return a.y>b.y;
    return a.x<b.x;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        for(int i=0;i<k;i++)
        {
            scanf("%d%d",&p[i].x,&p[i].y);
        }
        sort(p,p+k,cmp);
        scanf("%d",&q);
        for(int i=0;i<q;i++)
            scanf("%lld",&c[i]);
        for(int z=0;z<q;z++)
        {
            int id = 0;
            ll res = n;
            int ans = 0;
            ll x = 0, y = 0;
            memset(cnt,0,sizeof(cnt));
            memset(sum,0,sizeof(sum));
            for(int i=1;i<=n;i++)
            {
                if(res<1)break;
                while(id<k && p[id].x==i)
                {
                    if(p[id].y>res)
                    {
                        id++;
                        continue;
                    }
                    cnt[p[id].y]++;
                    x++;
                    sum[p[id].y]+=(i+p[id].y);
                    y+=(i+p[id].y);
                    id++;
                }
                while(1ll*x*(i+res)-1ll*y>c[z])
                {
                    if(cnt[res])
                    {
                        x-=cnt[res];
                        y-=sum[res];
                    }
                    res--;
                }
                if(res<1)break;
                if(x*(i+res)-y==c[z])
                {
                    ans++;
                    if(cnt[res])
                    {
                        x-=cnt[res];
                        y-=sum[res];
                    }
                    res--;
                }
            }
            if(z<q-1)
                printf("%d ",ans);
            else
                printf("%d\n",ans);
        }
    }
}


猜你喜欢

转载自blog.csdn.net/AmarisCR/article/details/86606045