bzoj4822[CQOI2017]:老C的任务(树状数组/k-dtree)

这里写图片描述

题解:树状数组或k-d树。

树状数组:

将数据离散化后将询问拆成左x和右x。依次加入点查询即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int Maxn=3e5+50;
inline int read()
{
    char ch=getchar();int i=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
    return i*f;
}

int n,m,x[Maxn],y[Maxn],totx,toty,tot,mx,my;
ll Bt[Maxn],ans[Maxn];

inline int lowbit(int x)
{
    return x&(-x);
}

inline void ins(int x,ll val)
{
    while(x<=mx)
    {
        Bt[x]+=val;
        x+=lowbit(x);
    }
}

inline ll get(int x)
{
    ll res=0;
    while(x>0)
    {
        res+=Bt[x];
        x-=lowbit(x);
    }
    return res;
}
struct point
{
    int x,y;
    ll pw;
}p[Maxn];

struct query
{
    int x1,y1,x2,y2;
}que[Maxn];

struct handle
{
    int x,pos,isque,cb;
    handle(){}
    handle(int x,int pos,int isque,int cb):x(x),pos(pos),isque(isque),cb(cb){}
    friend inline bool operator <(const handle &a,const handle &b)
    {
        if(a.x!=b.x)return a.x<b.x;
        else return a.isque<b.isque;
    }
}hd[Maxn];

inline void l_b()
{
    sort(x+1,x+totx+1);
    sort(y+1,y+toty+1);
    mx=unique(x+1,x+totx+1)-x-1;
    my=unique(y+1,y+toty+1)-y-1;
    for(int i=1;i<=n;i++)
    {
        p[i].x=lower_bound(x+1,x+mx+1,p[i].x)-x;
        p[i].y=lower_bound(y+1,y+my+1,p[i].y)-y;
    }
    for(int i=1;i<=m;i++)
    {
        que[i].x1=lower_bound(x+1,x+mx+1,que[i].x1)-x;
        que[i].x2=lower_bound(x+1,x+mx+1,que[i].x2)-x;
        que[i].y1=lower_bound(y+1,y+mx+1,que[i].y1)-y;
        que[i].y2=lower_bound(y+1,y+mx+1,que[i].y2)-y;
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        p[i].x=read(),p[i].y=read(),p[i].pw=read();
        x[++totx]=p[i].x;y[++toty]=p[i].y;
    }
    for(int i=1;i<=m;i++)
    {
        que[i].x1=read();
        x[++totx]=que[i].x1;
        que[i].y1=read();
        y[++toty]=que[i].y1;
        que[i].x2=read();
        x[++totx]=que[i].x2;
        que[i].y2=read();
        y[++toty]=que[i].y2;
    }
    l_b();
    for(int i=1;i<=n;i++)
    {
        hd[++tot]=handle(p[i].x,i,0,0);
    }
    for(int i=1;i<=m;i++)
    {
        hd[++tot]=handle(que[i].x1-1,i,1,-1);
        hd[++tot]=handle(que[i].x2,i,1,1);
    }
    sort(hd+1,hd+tot+1);
    for(int i=1;i<=tot;i++)
    {
        if(hd[i].isque)ans[hd[i].pos]+=((get(que[hd[i].pos].y2)-get(que[hd[i].pos].y1-1))*hd[i].cb);
        else ins(p[hd[i].pos].y,p[hd[i].pos].pw);
    }

    for(int i=1;i<=m;i++)
    cout<<ans[i]<<endl;
}
k-d树:

裸题,但会被卡20分。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
const int Maxn=1e5+50;
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
inline ll read()
{
    char ch=getchar();ll i=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}
    return i*f;
}

struct point
{
    ll x,y,pw;
    point(){}
    point(ll x,ll y):x(x),y(y),pw(0){}
}p[Maxn];

struct node
{
    node *lc,*rc;
    point x;
    ll mnx,mny,mxx,mxy,sum;
    node():lc(NULL),rc(NULL){}
    void upt()
    {
        if(lc)
        {
            mnx=min(mnx,lc->mnx);
            mny=min(mny,lc->mny);
            mxx=max(mxx,lc->mxx);
            mxy=max(mxy,lc->mxy);
            sum+=lc->sum;
        }
        if(rc)
        {
            mnx=min(mnx,rc->mnx);
            mny=min(mny,rc->mny);
            mxx=max(mxx,rc->mxx);
            mxy=max(mxy,rc->mxy);
            sum+=rc->sum;
        }
    }
}*rt,POOL[Maxn],*pool=POOL;

inline node* newnode(point x)
{
    ++pool;
    pool->x=x;
    pool->mnx=pool->mxx=x.x;
    pool->mny=pool->mxy=x.y;
    pool->sum=x.pw;
    return pool;
}

int n,Q;

inline bool comx(const point &x,const point &y)
{
    return x.x<y.x||(x.x==y.x&&x.y<y.y);
}
inline bool comy(const point &x,const point &y)
{
    return x.y<y.y||(x.y==y.y&&x.x<y.x);
}

inline void build(node *&now,int l,int r,int dim)
{
    if(l==r)
    {
        now=newnode(p[l]);
        return;
    }
    int mid=(l+r)>>1;
    if(!dim)nth_element(p+l,p+mid,p+r+1,comx);
    else nth_element(p+l,p+mid,p+r+1,comy);
    now=newnode(p[mid]);
    if(mid>l)build(now->lc,l,mid-1,dim^1);
    if(r>mid)build(now->rc,mid+1,r,dim^1);
    now->upt();
    return;
}

inline bool judgein(point x,ll mx1,ll my1,ll mx2,ll my2)
{
    return (x.x>=mx1&&x.x<=mx2&&x.y>=my1&&x.y<=my2);
}

inline bool judgeinsert(node *x,ll mx1,ll my1,ll mx2,ll my2)
{
    if(judgein(point(x->mnx,x->mny),mx1,my1,mx2,my2)||judgein(point(x->mnx,x->mxy),mx1,my1,mx2,my2)||judgein(point(x->mxx,x->mny),mx1,my1,mx2,my2)||judgein(point(x->mxx,x->mxy),mx1,my1,mx2,my2))return true;
    if(judgein(point(mx1,my1),x->mnx,x->mny,x->mxx,x->mxy)||judgein(point(mx1,my2),x->mnx,x->mny,x->mxx,x->mxy)||judgein(point(mx2,my1),x->mnx,x->mny,x->mxx,x->mxy)||judgein(point(mx2,my2),x->mnx,x->mny,x->mxx,x->mxy))return true;
    if(x->mnx<=mx1&&x->mxx>=mx2&&x->mny>=my1&&x->mxy<=my2)return true;
    if(x->mnx>=mx1&&x->mxx<=mx2&&x->mxy>=my2&&x->mny<=my1)return true;
    return false;
}
inline ll query(node *now,ll mx1,ll my1,ll mx2,ll my2)
{
    if(now->mnx>=mx1&&now->mny>=my1&&now->mxx<=mx2&&now->mxy<=my2)return now->sum;
    ll res=0;
    if(now->lc&&judgeinsert(now->lc,mx1,my1,mx2,my2))res+=query(now->lc,mx1,my1,mx2,my2);
    if(now->rc&&judgeinsert(now->rc,mx1,my1,mx2,my2))res+=query(now->rc,mx1,my1,mx2,my2);
    if(judgein(now->x,mx1,my1,mx2,my2))res+=now->x.pw;
    return res;
}
int main()
{
    n=read(),Q=read();
    for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read(),p[i].pw=read();
    build(rt,1,n,0);
    while(Q--)
    {
        ll mx1=read(),my1=read(),mx2=read(),my2=read();
        cout<<query(rt,mx1,my1,mx2,my2)<<endl;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值