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

    Luogu4169

    每次操作加入平面上一个点 , 或者询问离一个点最近的点的距离

    CDQ分治模板
    (1.)solve(l,mid);
    (2.)solve(mid+1,r);
    (3.)计算([l,mid])中修改操作对([mid+1,r])中查询操作的影响

    /*
    ----------------------
    [CDQ分治] 天使玩偶
    1.solve(l,mid);
    2.solve(mid+1,r);
    3.计算[l,mid]中修改操作对[mid+1,r]中查询操作的影响
    ----------------------
    对于这道题:
    假设只有修改,题目变成每次只有查询,询问到某个点最近的点距离:
    ans=Min(|X-x[i]|+|Y-y[i]|)
    对于绝对值,把它拆成四次解决.
    对于左下角的点:ans=X+Y-Max(x[i]+y[i])
    按x坐标排序满足了x[i]<=X的条件,BIT控制了y[i]<=Y的条件并维护了x[i]+y[i]的最大值
    对于左上角的点:ans=X-Y+Min(y[i]-x[i])=X-Y+Max(x[i]-y[i])
    具体四个方向的实现见李煜东的神奇操作
    ----------------------2018.12.26
    */
    #include<bits/stdc++.h>
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)<(y)?(x):(y))
    using namespace std;
    typedef long long LL;
    const int INF=1e9+7;
    inline LL read(){
        register LL x=0,f=1;register char c=getchar();
        while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
        while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
        return f*x;
    }
    
    const int MAXN=1000005;
    
    struct Node{
        int x,y,z;
        inline friend bool operator < (Node a,Node b){
            if(a.x==b.x) return a.y<b.y;
            return a.x<b.x;
        }
    }a[MAXN],b[MAXN];
    
    namespace BIT{
        int c[MAXN],Ctot;
        inline void insert(int x,int val){
            for(;x<Ctot;x+=x&-x) c[x]=Max(c[x],val);//前缀最大值
            //由于Ctot加了1,所以实际的Ctot没有到这么大(但Ctot对于query没有影响,所以加上等号也不会错)
        }
        inline int query(int x){
            int res=-(1<<30);
            for(;x;x-=x&-x) res=Max(res,c[x]);
            return res;
        }
        inline void cancel(int x){
            for(;x<Ctot;x+=x&-x) c[x]=-(1<<30);//全部赋为最小值
        }
    }using namespace BIT;
    
    int ans[MAXN];
    int n,m;
    
    // 求解简化版问题,需要考虑b[st~ed]的坐标,根据4个方向的不同,
    // 横坐标顺序为de(±1),树状数组维护的信息用系数dx,dy(±1)指定
    inline void cal(int st,int ed,int sign,int dx,int dy){
        for(int i=st;i!=ed;i+=sign){
            int y=dy==1?b[i].y:Ctot-b[i].y;//由于-b[i].y是负数,所以加上一个大数
            int val=dx*b[i].x+dy*b[i].y;
            if(a[b[i].z].z==1) insert(y,val);
            else ans[b[i].z]=Min(ans[b[i].z],abs(val-query(y)));
            //注意:query(y)并不就是答案,答案是(形如x[i]+y[i])与query(y)的差
        }
        for(int i=st;i!=ed;i+=sign){
            int y=dy==1?b[i].y:Ctot-b[i].y;
            if(a[b[i].z].z==1) cancel(y);//撤销修改
        }
    }
    
    inline void CDQ(int l,int r){
        int mid=(l+r)>>1;
        if(l<mid) CDQ(l,mid);
        if(mid+1<r) CDQ(mid+1,r);
        int t=0;
        for(int i=l;i<=r;i++){
            if(i<=mid&&a[i].z==1||i>mid&&a[i].z==2)
                b[++t]=a[i],b[t].z=i;
        }
        sort(b+1,b+t+1);
        cal(1,t+1,1,1,1);cal(t,0,-1,-1,-1);
        cal(1,t+1,1,1,-1);cal(t,0,-1,-1,1);
    }
    
    int main(){
        n=read(),m=read(),m+=n;
        for(int i=1;i<=n;i++)
            a[i].x=read(),a[i].y=read()+1,a[i].z=1;//注意:y坐标要加1,否则BIT会出错
        for(int i=n+1;i<=m;i++)
            a[i].z=read(),a[i].x=read(),a[i].y=read()+1;
        for(int i=1;i<=m;i++)
            Ctot=Max(Ctot,a[i].y);
        Ctot++;//同样要加1,应对y=Ctot-b[i].z的情况
        memset(c,0xcf,sizeof c);
        memset(ans,0x3f,sizeof ans);
        CDQ(1,m);
        for(int i=1;i<=m;i++)
            if(a[i].z==2) printf("%d
    ",ans[i]);
    }
    

    代码重构于19.4.3

  • 相关阅读:
    关于android4.3 bluetooth4.0的那些事儿
    一个比较简单的夜间模式实现
    Android类装载器DexClassLoader的简单使用-----制作android插件的前奏
    Android学习笔记之 网络状态监听
    Android 学习笔记之 SQLite基础用法
    Android 学习笔记之 JSON的序列化基本用法
    Android学习笔记之 仿QQ登录界面的实现
    Android学习笔记之 生成KeyStore和给apk添加签名
    ArcGis for Android学习笔记之AsyncTask和IdentifyTask的应用
    Android学习笔记之 jar包的导入和异常处理
  • 原文地址:https://www.cnblogs.com/lizehon/p/10647920.html
Copyright © 2011-2022 走看看