bzoj 4066: 简单题

 https://www.lydsy.com/JudgeOnline/problem.php?id=4066

很快就想到了,维护子树超平面,如果要求的范围完整包含这个子树,就直接加sum,否则看是否有相交,再考虑进入子树。

因为一直insert,kd树可能无法保证复杂度,所以要10000个点重构一次,复杂度是20*2e5复杂度

然后写完了,查了一晚上错,再重写了一遍,没找出来错误

然后开始二分抄代码,最后几乎全抄了才过了

心态崩了

弃疗.jpg

#include<bits/stdc++.h>
using namespace std;
 
const int maxl=2e5+10;
 
int n,idx,cnt,ans,root;
struct point
{
    int x[2],val;
    point(int a=0,int b=0,int c=0){ x[0]=a; x[1]=b; val=c; }
    inline int operator [] (int i){ return x[i]; }
    bool operator < (const point &b)const
    {
        return x[idx]<b.x[idx];
    }
}a[maxl];
struct kdtree
{
    int l,r,sum;
    int mi[2],mx[2];
    point t;
}tr[maxl];
 
inline void Update_mx(int &x,int y){ if(y>x) x=y; }

inline void Update_mi(int &x,int y){ if(y<x) x=y; }

void Update(int k){
    for(int i=0;i<2;i++){
        if(tr[k].l) Update_mx(tr[k].mx[i],tr[tr[k].l].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].l].mi[i]);
        if(tr[k].r) Update_mx(tr[k].mx[i],tr[tr[k].r].mx[i]),Update_mi(tr[k].mi[i],tr[tr[k].r].mi[i]);
    }
    tr[k].sum=tr[tr[k].l].sum+tr[tr[k].r].sum+tr[k].t.val;
}

 
void Rebuild(int &k,int l,int r,int d){
    idx=d; k=++cnt;
    int mid=(l+r)>>1;
    nth_element(a+l,a+mid,a+r+1);
    tr[k].t=a[mid];
    for(int i=0;i<2;i++) tr[k].mx[i]=tr[k].mi[i]=a[mid][i];
    if(l<mid) Rebuild(tr[k].l,l,mid-1,d^1);
    else tr[k].l=0;
    if(r>mid) Rebuild(tr[k].r,mid+1,r,d^1);
    else tr[k].r=0;
    Update(k);
}
 
void Insert(int &k,point pt,int d){
    if(!k){
        k=++cnt; tr[k].t=pt; tr[k].sum=pt.val;
        for(int i=0;i<2;i++) tr[k].mx[i]=tr[k].mi[i]=pt[i];
        return;
    }
    if(pt[0]==tr[k].t[0] && pt[1]==tr[k].t[1]){ tr[k].sum+=pt.val; tr[k].t.val+=pt.val; return; }
    idx=d;
    if(pt<tr[k].t) Insert(tr[k].l,pt,d^1);
    else Insert(tr[k].r,pt,d^1);
    Update(k);
}
 
inline void prework()
{
    scanf("%d",&n);
}
 
inline bool cross(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4){
    if(x2<x3 || x1>x4 || y2<y3 || y1>y4) return false;
    return true;
}
 
inline bool cover(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4){ //1-2 cover 3-4
    if(y1<=y3 && y2>=y4 && x2>=x4 && x1<=x3) return true;
    return false;
}
 
int Query(int k,int x1,int y1,int x2,int y2){
    if(cover(x1,y1,x2,y2,tr[k].mi[0],tr[k].mi[1],tr[k].mx[0],tr[k].mx[1])) return tr[k].sum;
    int tmp=0,l=tr[k].l,r=tr[k].r;
    if(x1<=tr[k].t.x[0] && tr[k].t.x[0]<=x2 && tr[k].t.x[1]>=y1 && tr[k].t.x[1]<=y2) 
        tmp+=tr[k].t.val;
    if(l && cross(x1,y1,x2,y2,tr[l].mi[0],tr[l].mi[1],tr[l].mx[0],tr[l].mx[1])) tmp+=Query(l,x1,y1,x2,y2);
    if(r && cross(x1,y1,x2,y2,tr[r].mi[0],tr[r].mi[1],tr[r].mx[0],tr[r].mx[1])) tmp+=Query(r,x1,y1,x2,y2);
    return tmp;
}
 
inline void mainwork()
{
    int flag=10000,op;
    while(~scanf("%d",&op)){
    	if(op==3) return;
        if(op==1){
            int x,y,c;
            //x=in()^ans; y=in()^ans; c=in()^ans;
            scanf("%d%d%d",&x,&y,&c);
            x^=ans;y^=ans;c^=ans;
			Insert(root,point(x,y,c),0);
            if(cnt==flag){
                for(int i=1;i<=cnt;i++) a[i]=tr[i].t,tr[i].sum=0;               
                int tmp=cnt; cnt=0; flag+=10000;
                Rebuild(root,1,tmp,0);
            }
        }
        else{
            int x1,y1,x2,y2;
            //x1=in()^ans; y1=in()^ans; x2=in()^ans; y2=in()^ans;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            x1^=ans;y1^=ans;x2^=ans;y2^=ans;
			printf("%d\n",ans=Query(root,x1,y1,x2,y2));
        }
    }
}
 
int main()
{
    prework();
    mainwork();
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值