2021“MINIEYE杯”中国大学生算法设计超级联赛(1)1010 zoto

https://acm.hdu.edu.cn/contests/contest_showproblem.php?cid=984&pid=1010

题意:

给出二维平面上的若干个点和若干个矩形,查询每个矩形内部有多少个y坐标不一样的点

莫队算法,将矩形按左右边界排序,查询上下边界的y坐标不一样的点

可以用数字证书,也可以继续分块

#include<bits/stdc++.h>

using namespace std;

#define N 100002

#define lowbit(x) (x&-x)

int f[N];
struct node
{
    int l,d,r,u;
    int id;
    int ans;
    int pos;
}e[N];

int c[N],sum[N]; 

int n,m,S;

bool cmp(node p,node q)
{
    if(p.pos!=q.pos) return p.pos<q.pos; 
    return p.r<q.r;
}

bool id(node p,node q)
{
    return p.id<q.id;
}

void add(int x,int y)
{
    while(x<N)
    {
        c[x]+=y;
        x+=lowbit(x);
    }
}

int query(int x)
{
    int cnt=0;
    while(x)
    {
        cnt+=c[x];
        x-=lowbit(x); 
    }
    return cnt;
}

void update(int x,int k)
{
    x=f[x];
    sum[x]+=k;
    if(k==1 && sum[x]==1) add(x,1);
    else if(k==-1 && !sum[x]) add(x,-1);
}

void solve()
{
    int l=1,r=0;
    for(int i=1;i<=m;i++)
    {
        while(l<e[i].l) update(l++,-1);
        while(l>e[i].l) update(--l,1);
        while(r<e[i].r) update(++r,1);
        while(r>e[i].r) update(r--,-1);
        e[i].ans=query(e[i].u)-query(e[i].d-1);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(c,0,sizeof(c));
        memset(sum,0,sizeof(sum));
        S=sqrt(n);
        for(int i=1;i<=n;i++) 
        {
            scanf("%d",&f[i]);
            ++f[i];
        }
        for(int i=1;i<=m;i++)
         {
            scanf("%d%d%d%d",&e[i].l,&e[i].d,&e[i].r,&e[i].u);
            e[i].u++;
            e[i].d++;
            e[i].id=i;
            e[i].pos=(e[i].l-1)/S+1;
        }
        sort(e+1,e+m+1,cmp);
        solve();
        sort(e+1,e+m+1,id);
        for(int i=1;i<=m;i++) printf("%d
",e[i].ans);
    }
}
作者:xxy
本文版权归作者和博客园共有,转载请用链接,请勿原文转载,Thanks♪(・ω・)ノ。
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/15070766.html