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

    Problem

    Problem
    Extra

    Solution

    考虑静态

    对于每一组询问((x,y))和现在已经确定的点(P = {(x_i,y_i)}),答案即为:
    (min_{1 le i le |P|}{|x - x_i| + |y - y_i|})

    发现有绝对值不太好整,考虑拆开,分成四种情况:
    (min_{1 le i le |P|,x_i le x,y_i le y} {x + y - (x_i + y_i)})
    (min_{1 le i le |P|,x_i ge x,y_i le y} {y - x - (y_i - x_i)})
    (min_{1 le i le |P|,x_i le x,y_i ge y} {x - y - (x_i - y_i)})
    (min_{1 le i le |P|,x_i ge x,y_i ge y} {-x - y - (-x_i - y_i)})
    然后取最小值。
    对于每个情况,变成了一个二位偏序,直接排序+BIT即可,BIT里面维护的是(dx cdot x + dy cdot y)的最大值,下标为(y)(dx,dy)按情况决定,例如第一个情况就是(dx = 1,dy = 1).
    如果有多组询问,那么就将询问和修改放在一起,然后按照(x)排序即可。

    化动为静

    使用cdq分治,对于cdq(l,r),先解决cdq(l,mid)和cdq(mid + 1,r),然后考虑左边的修改对右边询问的影响。
    这时候就可以转化问题:上面提到的(P)集合就是([l,mid])中的修改,询问就是([mid + 1,r])中的询问,进行四个情况分别处理即可。

    Code

    # include <bits/stdc++.h>
    using namespace std;
    
    const int N = 6e5 + 5,MAXY = 1e6 + 5;
    const int inf = 0x3f3f3f3f;
    
    int n,m;
    int Maxy = 0;
    
    struct Point
    {
        int x,y;
        Point() {}
        Point(int _x,int _y) : x(_x),y(_y) {}
    };
    
    struct query
    {
        int t,x,y;
    }Q[N],b[N];
    int ans[N];
    
    template <typename T> void read(T &x)
    {
        int w = 1;
        char ch = getchar();
        while(!isdigit(ch))
        {
            if(ch == '-') w = -1;
            ch = getchar();
        }
        while(isdigit(ch))
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        x *= w;
        return;
    }
    void write(int x)
    {
        if(x < 0) putchar('-'),x = -x;
        if(x >= 10) write(x / 10);
        char ch = (x % 10) + 48;
        putchar(ch);
        return;
    }
    
    struct BIT
    {
        int A[MAXY];
        int lowbit(int x) {return x & (-x);}
        void add(int x,int d)
        {
            while(x <= Maxy)
            {
                A[x] = max(A[x],d);
                x += lowbit(x);
            }
            return;
        }
        int query(int x)
        {
            int ans = -inf;
            while(x)
            {
                ans = max(ans,A[x]);
                x -= lowbit(x);
            }
            return ans;
        }
        void clear(int x,int d)
        {   
            while(x <= Maxy)
            {
                A[x] = d;
                x += lowbit(x);
            }
            return;
        }
    }T;
    
    bool compare(const struct query &x,const struct query &y)
    {
        if(x.x == y.x) return x.y < y.y;
        return x.x < y.x;
    }
    
    void solve(int l,int r,int opt) /*opt = 0 左下 opt = 1 左上 opt = 2 右下 opt = 3 右上*/
    {
        if(opt == 0) 
        {
            for(int i = l; i <= r; i++)
            {
                int sum = b[i].x + b[i].y;
                if(Q[b[i].t].t == 1) 
                {
                    T.add(b[i].y,sum);
                }
                else ans[b[i].t] = min(ans[b[i].t],abs(sum - T.query(b[i].y)));
            }
            for(int i = l; i <= r; i++) if(Q[b[i].t].t == 1) T.clear(b[i].y,-inf);
        }
        else if(opt == 1)
        {
            for(int i = l; i <= r; i++)
            {
                int sum = b[i].x - b[i].y;
                if(Q[b[i].t].t == 1)
                {
                    T.add(Maxy - b[i].y,sum);
                }
                else ans[b[i].t] = min(ans[b[i].t],abs(sum - T.query(Maxy - b[i].y)));
            }
            for(int i = l; i <= r; i++) 
            {
                if(Q[b[i].t].t == 1) T.clear(Maxy - b[i].y,-inf);
            }
        }
        else if(opt == 2)
        {
            for(int i = r; i >= l; i--)
            {
                int sum = b[i].y - b[i].x;
                if(Q[b[i].t].t == 1)
                {
                    T.add(b[i].y,sum);
                }
                else ans[b[i].t] = min(ans[b[i].t],abs(sum - T.query(b[i].y)));
            }
            for(int i = r; i >= l; i--)
            {
                if(Q[b[i].t].t == 1) T.clear(b[i].y,-inf);
            }
        }
        else
        {
            for(int i = r; i >= l;i--) 
            {
                int sum = -b[i].x - b[i].y;
                if(Q[b[i].t].t == 1)
                {
                    T.add(Maxy - b[i].y,sum);
                }
                else ans[b[i].t] = min(ans[b[i].t],abs(sum - T.query(Maxy - b[i].y)));
            }
            for(int i = r; i >= l; i--) 
            {
                if(Q[b[i].t].t == 1) T.clear(Maxy - b[i].y,-inf);
            }
        }
        return;
    }
    
    void CDQ(int l,int r)
    {
        if(l >= r) return;
        int mid = (l + r) >> 1;
        CDQ(l,mid),CDQ(mid + 1,r);
        int tot = 0;
        for(int i = l; i <= mid; i++) 
        {
            if(Q[i].t == 1) b[++tot] = Q[i],b[tot].t = i;
        }
        for(int i = mid + 1; i <= r; i++)
        {
            if(Q[i].t == 2)
            {
                b[++tot] = Q[i];b[tot].t = i;
            }
        }
        //将[l,mid]的修改和[mid + 1,r]的查询加入
        sort(b + 1, b + tot + 1, compare);
        for(int i = 0; i <= 3; i++) solve(1,tot,i);
        return;
    }
    
    int main(void)
    {
        read(n),read(m);
        for(int i = 1; i <= n; i++)
        {
            read(Q[i].x),read(Q[i].y);
            ++Q[i].x,++Q[i].y;
            Q[i].t = 1;
            Maxy = max(Maxy,Q[i].y);
        }
        for(int i = n + 1; i <= n + m; i++)
        {
            read(Q[i].t),read(Q[i].x),read(Q[i].y);
            ++Q[i].x,++Q[i].y;
            Maxy = max(Maxy,Q[i].y);
        }
        ++Maxy;
        for(int i = 1; i <= n + m; i++) ans[i] = inf;
        for(int i = 0; i <= Maxy; i++) T.A[i] = -inf;
        CDQ(1,n + m);
        for(int i = n + 1; i <= n + m; i++) if(Q[i].t == 2) {write(ans[i]);putchar('
    ');}
        return 0;
    }
    

    Tricks

    有一部分是要处理>部分的,因为这里的BIT维护的是最大值,所以不能用减的方法。考虑将整个树状数组倒序,第(i)个就变成了第(n - i)个,>也变成<,再进行处理即可。

  • 相关阅读:
    解决Enterprise Library January 2006不能加密配置文件的方法
    ASP.NET Ajax 和ASP.NET 2.0 的登陆控件相冲突的问题的讨论
    十二时辰与时间对照表,十二经络时辰表
    对表中数据逐行累加
    SQL脚本 CASE...WHEN...THEN...ELSE...END 的应用
    [转]看刚毕业MM如何在北京买房
    让你的GUI程序随WINDOWS服务一起启动
    启动Oracle,SQL服务,IIS脚本
    无论买新房还是二手房 教你六招可放心收房
    经典开源项目简介及源码下载
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/14773654.html
Copyright © 2011-2022 走看看