[BZOJ2716][Violet 3]天使玩偶(cdq分治+bit)

题目描述

传送门

题解

上下左右想想就不好搞啊…所以我们每一次只统计某个点左下方与它最近的,然后做4遍
|x-x’|+|y-y’|=(x+y)-(x’+y’),也就是求x+y最大的点
然后这不就和三维偏序问题差不多了么?
按照时间排序分治,每一次对(l,mid)和(mid+1,r)按照x排序,然后两个指针,对于每一个询问将横坐标都小于等于它的点按照y加入bit,权值为x+y,查询最大值

然而写完了之后狂T不止啊…这一波常数卡得
首先归并排序的方法确实要快很多
然后就是学了一点hxy的姿势:只有询问才加点,不是询问就不加,也就是能不做的就不做
sort慢

代码

#include
#include
#include
#include
#include
#include
using namespace std;
#define N 1000005

int n,m,opt,acnt,bcnt,pa,pb,tot,inf,INF;
int ans[N],ch[N];
struct hp{int x,y,id;bool flag;}p[N],q[N];
int C[N];

int read()
{
    int x=0;char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x;
}
void add(int loc,int val)
{
    if (!loc) return;
    for (int i=loc;i<=inf;i+=i&(-i))
        C[i]=max(C[i],val);
}
void cover(int loc)
{
    if (!loc) return;
    for (int i=loc;i<=inf;i+=i&(-i))
        C[i]=-1;
}
int query(int loc)
{
    int ans=-1;
    for (int i=loc;i>=1;i-=i&(-i))
        ans=max(ans,C[i]);
    return ans;
}
void cdq(int l,int r)
{
    if (l>=r) return;
    int mid=(l+r)>>1;
    pa=l,pb=mid+1;
    for (int i=l;i<=r;++i)
        if (p[i].id<=mid) q[pa++]=p[i];
        else q[pb++]=p[i];
    for (int i=l;i<=r;++i) p[i]=q[i];
    pa=l,pb=mid+1;tot=0;
    while (pb<=r)
    {
        if (p[pb].flag)
        {
            while (pa<=mid&&p[pa].x<=p[pb].x)
            {
                if(!p[pa].flag)add(p[pa].y,p[pa].x+p[pa].y);
                ch[++tot]=p[pa].y;
                ++pa;
            }
            int t=query(p[pb].y);
            if(t!=-1)ans[p[pb].id]=min(ans[p[pb].id],p[pb].x+p[pb].y-t);
        }
        ++pb;
    }
    for (int i=1;i<=tot;++i)cover(ch[i]);
    cdq(l,mid);
    cdq(mid+1,r);
}
int cmp(hp a,hp b){return a.xx;}
int main()
{
    n=read();m=read();
    for (int i=1;i<=n;++i)
    {
        p[i].x=read();p[i].y=read();
        p[i].id=i;
        inf=max(inf,p[i].x);inf=max(inf,p[i].y);
    }
    m+=n;
    for (int i=n+1;i<=m;++i)
    {
        opt=read();
        if(opt==2)p[i].flag=1;
        p[i].x=read();p[i].y=read();
        p[i].id=i;
        inf=max(inf,p[i].x);inf=max(inf,p[i].y);
    }
    memset(ans,127,sizeof(ans));INF=ans[0];
    memset(C,-1,sizeof(C));
    sort(p+1,p+m+1,cmp);cdq(1,m);
    for (int i=1;i<=m;++i)p[i].y=inf-p[i].y+1;sort(p+1,p+m+1,cmp);cdq(1,m);
    for (int i=1;i<=m;++i)p[i].x=inf-p[i].x+1;sort(p+1,p+m+1,cmp);cdq(1,m);
    for (int i=1;i<=m;++i)p[i].y=inf-p[i].y+1;sort(p+1,p+m+1,cmp);cdq(1,m);
    for (int i=n+1;i<=m;++i)
        if (ans[i]!=INF) printf("%d\n",ans[i]);
}

总结

①卡常数技巧:能不做的就不做。

你可能感兴趣的:(题解,cdq分治/整体二分,bit)