ural1707 线段树扫描线

这题卡了四五天了,从开始看题目就蛋疼了,看了不知道多少遍,再与队友分析了一下,总算明白了题意。

题意及思路:首先给出m组s0,t0,ds,dt,k; 由公式算出m*k个点;

                        然后给出p组a0,b0,c0,d0,da,db,dc,dd,q; 由公式算出q个矩形;

                        对于每个矩形是否有点在其内。

                       用线段树扫描线统计每一个点左下方点的个数,然后用标记映射到每一个矩形;

                       最后再拿统计矩形内点数( 右上+左下-右下-左上 )。


ACcode:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using std::sort;
using std::unique;

const int msize=1111111;
const int ksize=400;
const LL MOD=200904040963LL;

LL m7[ksize],res;
int sum[msize<<2];
int q[ksize],re[ksize];
int num[msize],X[msize];

struct Point
{
    int x,y;
    int f;
    Point() {}
    Point(int a,int b,int c):x(a),y(b),f(c) {}
    bool operator <(const Point &cmp) const{
        if (y!=cmp.y) return y<cmp.y;
        if (x!=cmp.x) return x<cmp.x;
        return f<cmp.f;
    }
} point[msize];

void Init()
{
    m7[0]=1;
    for (int i=1; i<=345; i++)
        m7[i]=(m7[i-1]*7)%MOD;
}

int Max(int a1,int a2)
{
    return a1>a2?a1:a2;
}

int Min(int a1,int a2)
{
    return a1<a2?a1:a2;
}

int Fin(int key,int len)
{
    int l=0,r=len;
    while (l<=r)
    {
        int m=(l+r)>>1;
        if (X[m]==key) return m;
        else if (X[m]<key) l=m+1;
        else r=m-1;
    }
    return -1;
}

void build(int rt,int l,int r)
{
    sum[rt]=0;
    if (l==r) return ;
    int m=(l+r)>>1;
    build(rt<<1,l,m);
    build(rt<<1|1,m+1,r);
}

void update(int rt,int l,int r,int pos)
{
    if (l==r)
    {
        sum[rt]++;
        return ;
    }
    int m=(l+r)>>1;
    if (pos<=m) update(rt<<1,l,m,pos);
    else update(rt<<1|1,m+1,r,pos);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

int query(int rt,int l,int r,int L,int R)
{
    if (L<=l&&r<=R) return sum[rt];
    int m=(l+r)>>1,ans=0;
    if (L<=m) ans+=query(rt<<1,l,m,L,R);
    if (R>m)  ans+=query(rt<<1|1,m+1,r,L,R);
    return ans;
}

int main()
{
    Init();
    int i,j,n,m;
    int x1,y1,x2,y2,p;
    int s0,t0,ds,dt,k;
    int cnt,len,pos,top;
    int a0,b0,c0,d0,da,db,dc,dd;
    while (~scanf("%d %d",&n,&m))
    {
        cnt=len=top=0;
        for (i=0; i<m; i++)
        {
            scanf("%d%d%d%d%d",&s0,&t0,&ds,&dt,&k);
            for (j=0; j<k; j++,top++)
            {
                X[len++]=s0;
                point[top]=Point(s0,t0,-1);
                s0=(s0+ds+n)%n,t0=(t0+dt+n)%n;
            }
        }
        scanf("%d",&p);
        for (i=0; i<p; i++)
        {
            scanf("%d%d%d%d%d%d%d%d%d",&a0,&b0,&c0,&d0,&da,&db,&dc,&dd,q+i);
            for (j=0; j<q[i]; j++)
            {
                x1=Min(a0,b0)-1,x2=Max(a0,b0);
                y1=Min(c0,d0)-1,y2=Max(c0,d0);
                X[len++]=x1,X[len++]=x2;
                point[top++]=Point(x1,y1,cnt),cnt++;
                point[top++]=Point(x1,y2,cnt),cnt++;
                point[top++]=Point(x2,y1,cnt),cnt++;
                point[top++]=Point(x2,y2,cnt),cnt++;
                a0=(a0+da+n)%n,b0=(b0+db+n)%n;
                c0=(c0+dc+n)%n,d0=(d0+dd+n)%n;
            }
        }
        sort(X,X+len);
        sort(point,point+top);
        len=unique(X,X+len)-X-1;
        build(1,0,len);
        for (i=0; i<top; i++)
        {
            k=point[i].f;
            pos=Fin(point[i].x,len);
            if (k<0) update(1,0,len,pos);
            else num[k]=query(1,0,len,0,pos);
        }
        for (t0=i=0; i<p; i++)
        {
            for (j=0; j<q[i]; j++)
            {
                k=num[t0+3]+num[t0]-num[t0+1]-num[t0+2];
                re[j]=k>0?1:0;
                t0+=4;
            }
            if (q[i]>20)
            {
                for (res=j=0; j<q[i]; j++)
                    res=(res+re[j]*m7[j])%MOD;
                printf("%lld",res);
            }
            else
                for (j=0; j<q[i]; j++) printf("%d",re[j]);
            puts("");
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值