1. 程式人生 > 實用技巧 >#cdq分治,樹狀陣列#洛谷 4169 [Violet]天使玩偶/SJY擺棋子

#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; 
}