zoukankan      html  css  js  c++  java
  • BZOJ2716 [Violet]天使玩偶(cdq分治+树状数组)

      非常裸的KD-tree。然而我没学啊。

      考虑如何离线求一个点在平面中的曼哈顿最近点。

      绝对值显得有点麻烦,于是把绝对值拆开分情况讨论一波。对于横坐标小于该点的,记录对于纵坐标的前缀x+y最大值和后缀x-y最大值;横坐标大于该点的,记录对于纵坐标的前缀y-x最大值和后缀-y-x最大值。

      不过这样不太方便,不如直接给点翻转一下换个坐标。这样就可以只用考虑左下的情况了。

      那么这个题,cdq分治就好了。注意树状数组不能有0下标,以及初值设为-inf。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 300010
    #define M 1000010
    #define inf 10000000
    int n,m,p,tree[M],stk[N<<5],top=0;
    struct data
    {
        int op,x,y,i,ans;
        bool operator <(const data&a) const
        {
            return x<a.x||x==a.x&&i<a.i;
        }
    }q[N],t[N];
    struct data2
    {
        int x,y;
        bool operator <(const data2&a) const
        {
            return x<a.x;
        }
    }a[N];
    bool cmp(const data&a,const data&b)
    {
        return a.i<b.i;
    }
    void update(int k,int x){while (k<=p){stk[++top]=k;tree[k]=max(tree[k],x);k+=k&-k;}}
    int getans(int k){int s=-inf;while (k){s=max(s,tree[k]);k-=k&-k;}return s;}
    void solve(int l,int r)
    {
        if (l==r) return;
        int mid=l+r>>1;
        solve(l,mid);
        solve(mid+1,r);
        int i=l,j=mid+1;
        for (int k=l;k<=r;k++)
        if (q[i]<q[j]&&i<=mid||j>r) t[k]=q[i++];
        else t[k]=q[j++];
        for (int k=l;k<=r;k++) q[k]=t[k];
        for (int k=l;k<=r;k++)
        if (q[k].op==1&&q[k].i<=mid) update(q[k].y,q[k].x+q[k].y);
        else if (q[k].op==2&&q[k].i>mid) q[k].ans=min(q[k].ans,q[k].x+q[k].y-getans(q[k].y));
        while (top) tree[stk[top--]]=-inf;
    }
    void work()
    {
        memset(tree,200,sizeof(tree));
        sort(a,a+m+1);sort(q,q+n+1);
        int j=0;
        for (int i=1;i<=n;i++)
        if (q[i].op==2)
        {
            while (j<m&&a[j+1].x<=q[i].x) j++,update(a[j].y,a[j].x+a[j].y);
            q[i].ans=min(q[i].ans,q[i].x+q[i].y-getans(q[i].y));
        }
        memset(tree,200,sizeof(tree));
        sort(q,q+n+1,cmp);
        top=0;
        solve(1,n);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj2716.in","r",stdin);
        freopen("bzoj2716.out","w",stdout);
        const char LL[]="%I64d";
    #else
        const char LL[]="%lld";
    #endif
        m=read(),n=read();
        for (int i=1;i<=m;i++) p=max(p,max(a[i].x=read()+1,a[i].y=read()+1)+1);
        for (int i=1;i<=n;i++) q[i].op=read(),p=max(p,max(q[i].x=read()+1,q[i].y=read()+1)+1),q[i].i=i,q[i].ans=inf;
        work();
        for (int i=1;i<=m;i++) a[i].x=p-a[i].x;
        for (int i=1;i<=n;i++) q[i].x=p-q[i].x;
        work();
        for (int i=1;i<=m;i++) a[i].y=p-a[i].y;
        for (int i=1;i<=n;i++) q[i].y=p-q[i].y;
        work();
        for (int i=1;i<=m;i++) a[i].x=p-a[i].x;
        for (int i=1;i<=n;i++) q[i].x=p-q[i].x;
        work();
        sort(q+1,q+n+1,cmp);
        for (int i=1;i<=n;i++)
        if (q[i].op==2) printf("%d
    ",q[i].ans);
        return 0;
    }
  • 相关阅读:
    代码管理模型概况
    循环链表
    队列

    链表
    java 2020-10-12T11:22:49.000+0800 字符串转换成正常时间格式
    动态数组
    mysql练习
    复杂度与LeetCode
    记一次带逗号的数字类型处理
  • 原文地址:https://www.cnblogs.com/Gloid/p/9452704.html
Copyright © 2011-2022 走看看