zoukankan      html  css  js  c++  java
  • [bzoj] 2716 天使玩偶 || CDQ分治

    原题

    已知n个点有天使玩偶,有m次操作:
    操作1:想起来某个位置有一个天使玩偶
    操作2:询问离当前点最近的天使玩偶的曼哈顿距离


    显然的CDQ问题,三维分别为时间,x轴,y轴。
    但是这道题的问题在于最近距离怎么维护。
    曼哈顿距离定义为|x2-x1|+|y2-y1|,所以把绝对值展开后一共有四种情况:
    (x2-x1+y2-y1 => x2+y2-(x1+y1) x1-x2+y2-y1 => -x2+y2+(x1-y1) x2-x1+y1-y2 => x2-y2+(y1-x1) x1-x2+y1-y2 => -x2-y2+(x1+y1))
    所以把四种情况都讨论一遍,每次处理为该情况的点对即可。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define N 500010
    using namespace std;
    int n,m,op,ans[N],mxy,f[1000010];
    struct hhh
    {
        int x,y,tm,op,num;
        bool operator < (const hhh &b) const
    	{
    	    return tm<b.tm;
    	}
    }p[2*N],tmp[2*N];
    
    int read()
    {
        int ans=0,fu=1;
        char j=getchar();
        for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
        for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
        return ans*fu;
    }
    
    inline void add(int x,int y)
    {
        while (x<=mxy) f[x]=max(f[x],y),x+=x&-x;
    }
    
    inline int query(int x)
    {
        int ans=0xc0c0c0c0;
        while (x) ans=max(ans,f[x]),x-=x&-x;
        return ans;
    }
    
    inline void clear(int x)
    {
        while (x<=mxy) f[x]=0xc0c0c0c0,x+=x&-x;
    }
    
    void solve(int l,int r)
    {
        if (l==r) return ;
        int mid=(l+r)>>1;
        solve(l,mid);
        solve(mid+1,r);
        int l1=l,l2=mid+1;
        for (int i=l;i<=r;i++)
        {
    	if (l1<=mid && (l2>r || p[l1].x<p[l2].x)) tmp[i]=p[l1++];
    	else tmp[i]=p[l2++];
        }
        
        for (int i=l;i<=r;i++)
        {
    	p[i]=tmp[i];
    	if (p[i].tm>mid && p[i].op) ans[p[i].num]=min(ans[p[i].num],p[i].x+p[i].y-query(p[i].y));
    	if (p[i].tm<=mid && !p[i].op) add(p[i].y,p[i].x+p[i].y);
        }
        for (int i=l;i<=r;i++)
        {
    	if (p[i].tm<=mid && !p[i].op)
    	    clear(p[i].y);
        }
        
        for (int i=l;i<=r;i++)
        {
    	if (p[i].tm>mid && p[i].op) ans[p[i].num]=min(ans[p[i].num],p[i].x-p[i].y-query(mxy-p[i].y));
    	if (p[i].tm<=mid && !p[i].op) add(mxy-p[i].y,p[i].x-p[i].y);
        }
        for (int i=l;i<=r;i++)
        {
    	if (p[i].tm<=mid && !p[i].op)
    	    clear(mxy-p[i].y);
        }
        
        for (int i=r;i>=l;i--)
        {
    	if (p[i].tm>mid && p[i].op) ans[p[i].num]=min(ans[p[i].num],-p[i].x+p[i].y-query(p[i].y));
    	if (p[i].tm<=mid && !p[i].op) add(p[i].y,p[i].y-p[i].x);
        }
        for (int i=r;i>=l;i--)
        {
    	if (p[i].tm<=mid && !p[i].op)
    	    clear(p[i].y);
        }
        
        for (int i=r;i>=l;i--)
        {
    	if (p[i].tm>mid && p[i].op) ans[p[i].num]=min(ans[p[i].num],-p[i].x-p[i].y-query(mxy-p[i].y));
    	if (p[i].tm<=mid && !p[i].op) add(mxy-p[i].y,-p[i].x-p[i].y);
        }
        for (int i=r;i>=l;i--)
        {
    	if (p[i].tm<=mid && !p[i].op)
    	    clear(mxy-p[i].y);
        }
    }
        
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        n=read();
        m=read();
        for (int i=1;i<=n;i++)
        {
    	p[i].x=read()+1;
    	p[i].y=read()+1;
    	p[i].tm=i;
    	mxy=max(mxy,p[i].y);
        }
        for (int i=1;i<=m;i++)
        {
    	op=read();
    	p[n+i].x=read()+1;
    	p[n+i].y=read()+1;
    	p[n+i].tm=n+i;
    	mxy=max(mxy,p[n+i].y);
    	if (op==2)
    	    p[n+i].num=++ans[0],p[n+i].op=1;
        }
        for (int i=1;i<=ans[0];i++) ans[i]=0x3f3f3f3f;
        mxy++;
        for (int i=0;i<=mxy;i++) f[i]=0xc0c0c0c0;
        sort(p+1,p+n+m+1);
        solve(1,n+m);
        for (int i=1;i<=ans[0];i++)
    	printf("%d
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    二、java 与 scala相互调用
    Gradle Tips#1-tasks
    Guice 学习(六)使用Provider注入服务( Provider Inject Service)
    C++第15周(春)项目3
    cocos2d-x3.2中怎样优化Cocos2d-X游戏的内存
    jqGrid源代码分析(一)
    OCP-1Z0-051-题目解析-第6题
    PHP连接sql server 2005环境配置
    【剑指offer】替换字符串中的空格
    android 推断Apk是否签名和 签名是否一致
  • 原文地址:https://www.cnblogs.com/mrha/p/8057874.html
Copyright © 2011-2022 走看看