#cdq分治,树状数组#洛谷 4169 [Violet]天使玩偶/SJY摆棋子

题目


分析

首先如果不会\(\text{K-DTree}\)的话,那就用CDQ分治吧
这题首先要去绝对值,分四种情况讨论, 只判断左下角的点
然后考虑怎样求最大值,这里采用树状数组,反正只是单点修改单点查询,
而且树状数组常数小,可以用树状数组实现,下标为纵坐标,存入横纵坐标之和
类似于归并排序的方法按照横坐标排序,处理\([l,mid]\)的区间来解决\([mid+1,r]\)的问题


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
const int N=600011; bool nee[N];
struct rec{int x,y,rk; bool ne;}Q[N<<1],q[N];
int c[N<<1],ans[N],mx,my,mmx,mmy,n,m;
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
inline void Min(int &a,int b){if (a>b) a=b;}
inline void Max(int &a,int b){if (a<b) a=b;}
inline void updzro(int x){for (;x<=mmy;x+=-x&x) if (c[x]) c[x]=0; else return;}
inline void update(int x,int y){for (;x<=mmy;x+=-x&x) Max(c[x],y);}
inline signed query(int x){rr int ans=0; for (;x;x-=-x&x) Max(ans,c[x]); return ans;}
inline void CDQ(int l,int r){
    if (l==r) return;
    rr int mid=(l+r)>>1,j=l;
    CDQ(l,mid),CDQ(mid+1,r);
    for (rr int i=mid+1;i<=r;++i)
    if (Q[i].ne){
        for (;j<=mid&&Q[j].x<=Q[i].x;++j)
            if (!Q[j].ne) update(Q[j].y,Q[j].x+Q[j].y);
        rr int t=query(Q[i].y);
        if (t) Min(ans[Q[i].rk],Q[i].x+Q[i].y-t);
    }
    for (rr int i=l;i<j;++i)
    if (!Q[i].ne) updzro(Q[i].y);
    rr int i1=l,j1=mid+1,cnt=0;
    for (;i1<=mid&&j1<=r;)
    if (Q[i1].x<=Q[j1].x) q[++cnt]=Q[i1],++i1;
        else q[++cnt]=Q[j1],++j1;
    for (;i1<=mid;++i1) q[++cnt]=Q[i1];
    for (;j1<=r;++j1) q[++cnt]=Q[j1];
    for (rr int i=l;i<=r;++i) Q[i]=q[i-l+1];
}
inline void Clear(bool ne1,bool ne2){
    mmx=mmy=m=0; rr rec T;
    for (rr int i=1;i<=n;++i) Q[i]=Q[i+n];
    if (ne1) for (rr int i=1;i<=n;++i) Q[i].x=mx-Q[i].x+1;
    if (ne2) for (rr int i=1;i<=n;++i) Q[i].y=my-Q[i].y+1;
    for (rr int i=1;i<=n;++i) if (Q[i].ne)
        Max(mmx,Q[i].x),Max(mmy,Q[i].y);
    for (rr int i=1;i<=n;++i)
    if (Q[i].x<=mmx&&Q[i].y<=mmy) T=Q[++m],Q[m]=Q[i],Q[i]=T;
}
signed main(){
    n=iut(),m=iut(),memset(ans,42,sizeof(ans));
    for (rr int i=1;i<=n;++i){
        rr int x=iut()+1,y=iut()+1;
        Q[i]=(rec){x,y,i,0},Max(mx,x),Max(my,y);
        nee[i]=0;
    }
    while (m--){
        rr int z=iut()-1,x=iut()+1,y=iut()+1;
        Q[++n]=(rec){x,y,n,z},Max(mx,x),Max(my,y),nee[n]=z;
    }
    for (rr int i=1;i<=n;++i) Q[i+n]=Q[i];
    Clear(0,0),CDQ(1,m),Clear(1,0),CDQ(1,m),
    Clear(0,1),CDQ(1,m),Clear(1,1),CDQ(1,m);
    for (rr int i=1;i<=n;++i)
        if (nee[i]) print(ans[i]),putchar(10);
    return 0; 
}
posted @ 2020-08-09 21:26  lemondinosaur  阅读(140)  评论(0编辑  收藏  举报