BZOJ2716: [Violet 3]天使玩偶(CDQ分治)

传送门

题意:
给n个点,每个点出现有先后顺序,求给定位置在给定时间曼哈顿距离最近的点。

题解:CDQ分治
感觉自己CDQ写炸了,常数很大。

首先拆分成4个区域。
考虑j点对i位置的贡献
首先有 tj<ti
1. xj>xi,yj>yi ,此时贡献为 xj+yjxiyi 。使 xj+yj 最小。
2. xj>xi,yj<yi ,此时贡献为 xj+yixiyj 。使 xjyj 最小。
3. xj<xi,yj>yi ,此时贡献为 xi+yjxjyi 。使 yjxj 最小。
4. xj<xi,yj<yi ,此时贡献为 xi+yixiyi 。使 xi+yj 最大。

又是三维偏序,分别用4个树状数组维护即可。

#include
using namespace std;

inline int read()
{
    char ch=getchar();int i=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
    return i*f;
}

int buf[50];
inline void W(int x)
{
    if(!x){putchar('0');return;}
    if(x<0){putchar('-');x=-x;}
    while(x)buf[++buf[0]]=x%10,x/=10;
    while(buf[0])putchar(buf[buf[0]--]+'0');
}

const int Maxn=5e5+50;
const int INF=0x3f3f3f3f;
int n,m,lim,ans[4][Maxn],cnt,cnt2,X[Maxn],Y[Maxn],bit[3][Maxn*2];
struct node
{
    int type,x,y,id;
}q1[Maxn*2],q2[Maxn*2],tmp[Maxn*2];

inline void insertmax1(int pos,int val){for(;pos<=lim;pos+=(pos&(-pos)))bit[0][pos]=max(bit[0][pos],val);}
inline int querymax1(int pos)
{
    int res=-INF;
    for(;pos;pos-=(pos&(-pos)))res=max(res,bit[0][pos]);
    return res;
}
inline void clearmax1(int pos){for(;pos<=lim;pos+=(pos&(-pos)))bit[0][pos]=-INF;}
inline void insertmin2(int pos,int val){for(;pos<=lim;pos+=(pos&(-pos)))bit[2][pos]=min(bit[2][pos],val);}
inline int querymin2(int pos)
{
    int res=INF;
    for(;pos;pos-=(pos&(-pos)))res=min(res,bit[2][pos]);
    return res;
}
inline void clearmin2(int pos){for(;pos<=lim;pos+=(pos&(-pos)))bit[2][pos]=INF;}
inline void insertmin1(int pos,int val){for(;pos;pos-=(pos&(-pos)))bit[1][pos]=min(bit[1][pos],val);}
inline int querymin1(int pos)
{
    int res=INF;
    for(;pos<=lim;pos+=(pos&(-pos)))res=min(res,bit[1][pos]);
    return res;
}
inline void clearmin1(int pos){for(;pos;pos-=(pos&(-pos)))bit[1][pos]=INF;}
inline void solve(int l,int r)
{
    if(l==r)return;
    int mid=(l+r)>>1;
    solve(l,mid);
    solve(mid+1,r);
    int head1=l,head2=mid+1,pos=l;
    for(int i=l;i<=r;i++)tmp[i]=q1[i];
    while(head1<=mid&&head2<=r)
    {
        if(tmp[head1].x<=tmp[head2].x)
        {
            if(tmp[head1].type==1)
            {
                insertmax1(tmp[head1].y,tmp[head1].x+tmp[head1].y);
                insertmin1(tmp[head1].y,tmp[head1].y-tmp[head1].x);
            }
            q1[pos++]=tmp[head1++];
        }
        else
        {
            if(tmp[head2].type==2)
            {
                ans[0][tmp[head2].id]=max(ans[0][tmp[head2].id],querymax1(tmp[head2].y));
                ans[1][tmp[head2].id]=min(ans[1][tmp[head2].id],querymin1(tmp[head2].y));
            }
            q1[pos++]=tmp[head2++];
        }
    }
    while(head1<=mid)
    {
        if(tmp[head1].type==1)
        {
            insertmax1(tmp[head1].y,tmp[head1].x+tmp[head1].y);
            insertmin1(tmp[head1].y,tmp[head1].y-tmp[head1].x);
        }
        q1[pos++]=tmp[head1++];
    }
    while(head2<=r)
    {
        if(tmp[head2].type==2)
        {
            ans[0][tmp[head2].id]=max(ans[0][tmp[head2].id],querymax1(tmp[head2].y));
            ans[1][tmp[head2].id]=min(ans[1][tmp[head2].id],querymin1(tmp[head2].y));
        }
        q1[pos++]=tmp[head2++];
    }
    for(int i=l;i<=mid;i++)if(tmp[i].type==1)clearmax1(tmp[i].y),clearmin1(tmp[i].y);
    head1=l,head2=mid+1,pos=l;
    for(int i=l;i<=r;i++)tmp[i]=q2[i];
    while(head1<=mid&&head2<=r)
    {
        if(tmp[head1].x>=tmp[head2].x)
        {
            if(tmp[head1].type==1)
            {
                insertmin1(tmp[head1].y,tmp[head1].x+tmp[head1].y);
                insertmin2(tmp[head1].y,tmp[head1].x-tmp[head1].y);
            }
            q2[pos++]=tmp[head1++];
        }
        else
        {
            if(tmp[head2].type==2)
            {
                ans[3][tmp[head2].id]=min(ans[3][tmp[head2].id],querymin1(tmp[head2].y));
                ans[2][tmp[head2].id]=min(ans[2][tmp[head2].id],querymin2(tmp[head2].y));
            }
            q2[pos++]=tmp[head2++];
        }
    }
    while(head1<=mid)
    {
        if(tmp[head1].type==1)
        {
            insertmin1(tmp[head1].y,tmp[head1].x+tmp[head1].y);
            insertmin2(tmp[head1].y,tmp[head1].x-tmp[head1].y);
        }
        q2[pos++]=tmp[head1++];
    }
    while(head2<=r)
    {
        if(tmp[head2].type==2)
        {
            ans[3][tmp[head2].id]=min(ans[3][tmp[head2].id],querymin1(tmp[head2].y));
            ans[2][tmp[head2].id]=min(ans[2][tmp[head2].id],querymin2(tmp[head2].y));
        }
        q2[pos++]=tmp[head2++];
    }
    for(int i=l;i<=mid;i++)if(tmp[i].type==1)clearmin1(tmp[i].y),clearmin2(tmp[i].y);
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
    {
        q1[++cnt].x=read();
        q1[cnt].y=read();
        q1[cnt].type=1;
        lim=max(q1[cnt].y,lim);
    }
    for(int i=1;i<=m;i++)
    {
        q1[++cnt].type=read();
        if(q1[cnt].type!=1)
        {
            ++cnt2;
            X[cnt2]=q1[cnt].x=read();
            Y[cnt2]=q1[cnt].y=read();
            q1[cnt].id=cnt2;
        }
        else
        {
            q1[cnt].x=read();
            q1[cnt].y=read();
        }
        lim=max(q1[cnt].y,lim);
    }
    memcpy(q2,q1,sizeof(q1));
    for(int i=1;i<=lim;i++)bit[0][i]=-INF;
    memset(bit[1],0x3f,sizeof(bit[1]));
    memset(bit[2],0x3f,sizeof(bit[2]));
    for(int i=1;i<=cnt2;i++)ans[0][i]=-INF;
    memset(ans[1],0x3f,sizeof(ans[1]));
    memset(ans[2],0x3f,sizeof(ans[2]));
    memset(ans[3],0x3f,sizeof(ans[3]));
    solve(1,n+m);
    for(int i=1;i<=cnt2;i++)
    {
        W(min( X[i]+Y[i]-ans[0][i] ,min( X[i]-Y[i]+ans[1][i] ,min( Y[i]-X[i]+ans[2][i] , ans[3][i]-X[i]-Y[i] ))));
        putchar('\n');
    }
}

你可能感兴趣的:(分治)