zoukankan      html  css  js  c++  java
  • Luogu P4169 [Violet]天使玩偶/SJY摆棋子

    传送门

    二维平面修改+查询,cdq分治可以解决。

    求关于某个点曼哈顿距离(x,y坐标)最近的点——dis(A,B) = |Ax-Bx|+|Ay-By|

    但是如何去掉绝对值呢?

    查看题解发现假设所有的点都在查询点的左下方,dis(A,B) = (Ax-Bx)+(Ay-By) = (Ax+Ay)-(Bx+By)

    只要求满足Bx<Ax,By<Ay且Bx,By之和最大的点就好了。

    那么如何把所有的点转化到该查询的左下呢?

    对于每个查询,可以把一、二、四象限的点都通过对称转移到第三象限。但查询很多,不可能一个个翻转。

    换个思路,如果把整个平面翻转三次,进行四次cdq分治,每次都只考虑左下的点,所有的点就都遍历到了!

    记录最大的x或y值为边界len,每次沿len翻转。例如沿y轴翻转时,x = len-x

    那么每个操作有三维——时间、x坐标、y坐标

    时间在输入时已经排好了;x归并排序;y仿照陌上花开,用树状数组记录。

    优化 & 注意

    这道题坑点超级多...而且四次cdq分治会得到一个感人的复杂度,所以必须考虑优化,卡一卡常数(我选择吸氧)

    • cdq内的归并排序代替每次sort。
    • 因为每次cdq完顺序会被打乱,如果重新按时间O(nlogn)排序,不如每次存入一个临时数组,然后O(n)直接复制过去。

      但是ans需要存入初始的数组中,所以结构体需要一个.id来记录打乱前的时间,也就是原数组下标。赋值应该写a[b[t2].id].ans,而不是a[t2].ans。

      并且,由于每次查询点的x,y也会更改,所以ans里不能直接存max(Bx+By),而应该为min((Ax+Ay)-(Bx+By))。

    • 如果某个点在坐标轴上,那么它的x或y为0。存入树状数组时,会因为lowbit()==0而陷入死循环。所以存入时,将x,y分别+1。

      同样的,如果某个点在翻转边界len上,翻转时也会变为0。所以len也要++。

    • 考虑这样一种情况:某一点非常靠近边界,导致某次翻转时,没有点在它的左下。这样查询时默认返回了0。

      当前的“原点”比实际上的点离该查询点更近,这样最终的距离就成了这个点到原点的距离,但原点是不存在的(经过刚刚的更改,已经没有x或y坐标为0的点)

      为避免这种情况,当查询时需要特判,若为0则返回-INF。

    • 由于初始值——前n个点一定是修改操作,可以把它们直接排好序,不用递归检验是否有查询。(不过我觉得有点麻烦就没写)

    这道题的代码不难,但是细节特别多,很难debug...写的时候思路一定要清晰了!

    代码如下

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<iostream>
    #define MogeKo qwq
    using namespace std;
    const int maxn = 1e7+10;
    const int INF = 2e7+10;
    int n,q,opt,x,y,len;
    
    struct node {
        int x,y,type,id,ans;
    } a[maxn],b[maxn],tem[maxn];
    
    struct BIT {
        int m[maxn];
        int lowbit(int x) {
            return x & -x;
        }
        void update(int x,int v) {
            for(; x <= len; x+= lowbit(x))
                m[x] = max(m[x],v);
        }
        int query(int x) {
            int ans = 0;
            for(; x; x-=lowbit(x))
                ans = max(ans,m[x]);
            return ans?ans:-INF;
        }
        void clear(int x) {
            for(; m[x]; x+= lowbit(x))
                m[x] = 0;
        }
    } tree;
    
    void cdq(int L,int R) {
        if(L == R) return;
        int mid = L+R >> 1;
        cdq(L,mid),cdq(mid+1,R);
        int t1 = L,t2 = mid+1;
        int k = L;
        while(t2 <= R) {
            while(t1 <= mid && b[t1].x <= b[t2].x) {
                if(b[t1].type == 1)
                    tree.update(b[t1].y, b[t1].x+b[t1].y);
                tem[k++] = b[t1++];
            }
            if(b[t2].type == 2)
                a[b[t2].id].ans = min(a[b[t2].id].ans,b[t2].x+b[t2].y-tree.query(b[t2].y));
            tem[k++] = b[t2++];
        }
        for(int i = L; i <= t1-1; i++)
            if(b[i].type == 1) tree.clear(b[i].y);
        while(t1 <= mid) tem[k++] = b[t1++];
        for(int i = L;i <= R;i++) b[i] = tem[i];
    }
    
    void solve(int rx,int ry) {
        for(int i = 1; i <= n+q; i++) {
            b[i] = a[i];
            if(rx) b[i].x = len - b[i].x;
            if(ry) b[i].y = len - b[i].y;
        }
        cdq(1,n+q);
    }
    
    int main() {
        scanf("%d%d",&n,&q);
        for(int i = 1; i <= n; i++) {
            scanf("%d%d",&x,&y);
            a[i].type = 1;
            a[i].id = i;
            a[i].x = ++x;
            a[i].y = ++y;
            len = max(len,max(x,y));
        }
        for(int i = n+1; i <= n+q; i++) {
            scanf("%d%d%d",&opt,&x,&y);
            a[i].type = opt;
            a[i].id = i;
            a[i].x = ++x;
            a[i].y = ++y;
            a[i].ans = INF;
            len = max(len,max(x,y));
        }
        len++;
        solve(0,0),solve(0,1),solve(1,0),solve(1,1);
        for(int i = n+1; i <= n+q; i++)
            if(a[i].type == 2) printf("%d
    ",a[i].ans);
        return 0;
    }
    View Code
  • 相关阅读:
    .NET微信网页开发之JS-SDK使用步骤和配置信息timestamp(时间戳),nonceStr(随机串),signature(签名),access_token(接口调用凭据)的生成获取讲解
    .NET项目中NLog的配置与使用
    ASP.NET MVC中使用jQuery Ajax通过FormData对象异步提交图片文件到服务端保存并返回保存的图片路径
    Linux CentOS上安装 MySQL 8.0.16
    微信小程序开发之多图片上传+.NET WebAPI后端服务保存图片资源
    MySQL 查询重复数据,删除重复数据保留id最小的一条作为唯一数据
    .NET轻松实现支付宝服务窗网页授权并获取用户相关信息
    .NET微信网页开发之通过UnionID机制,解决用户在不同公众号,或在公众号、移动应用之间帐号统一问题
    Navicat远程连接MySQL 提示1045
    Vs Code推荐安装插件
  • 原文地址:https://www.cnblogs.com/mogeko/p/10503518.html
Copyright © 2011-2022 走看看