• Violet 3 杯省选模拟赛 天使玩偶


    https://vjudge.net/problem/HYSBZ-2716

    https://ac.nowcoder.com/acm/problem/51118

    题目

    Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下。而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它。

    我们把 Ayu 生活的小镇看作一个二维平面坐标系,而 Ayu 会不定时地记起可能在某个点 (x,y) 埋下了天使玩偶;或者 Ayu 会询问你,假如她在 (x,y) ,那么她离近的天使玩偶可能埋下的地方有多远。

    因为 Ayu 只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为dist(A,B)=|Ax-Bx|+|Ay-By|。其中 Ax 表示点 A的横坐标,其余类似。

    Input

    第一行包含两个整数n和m ,在刚开始时,Ayu 已经知道有n个点可能埋着天使玩偶, 接下来 Ayu 要进行m 次操作

    接下来n行,每行两个非负整数 (xi,yi),表示初始n个点的坐标。

    再接下来m 行,每行三个非负整数 t,xi,yi。

    如果t=1 ,则表示 Ayu 又回忆起了一个可能埋着玩偶的点 (xi,yi)。

    如果t=2 ,则表示 Ayu 询问如果她在点 (xi,yi) ,那么在已经回忆出来的点里,离她近的那个点有多远

    Output

    对于每个t=2 的询问,在单独的一行内输出该询问的结果。

    题解

    因为是曼哈顿距离,所以距离可以写成$leftlvert x-x_i ight vert+leftlvert y-y_i ight vert$,去掉绝对值可以分成4种情况

    1. $x<x_i$,$y<y_i$
    2. $x<x_i$,$ygeqslant y_i$
    3. $xgeqslant x_i$,$y<y_i$
    4. $xgeqslant x_i$,$ygeqslant y_i$

    距离就变成以下四种情况

    • $-x-y+x_i+y_i=(-x-y)-(x_i-y_i)$
    • $-x+y+x_i-y_i=(-x+y)-(-x_i+y_i)$
    • $x-y-x_i+y_i=(x-y)-(x_i-y_i)$
    • $x+y-x_i-y_i=(x+y)-(x_i+y_i)$

    可以看到符号都统一了,而且距离可以分成查询的坐标和知道的坐标两部分,只用保存后面那一部分的和的最大值,就可以得到距离的最小值。

    如果不考虑在序列中新增操作2,那么题目要求是在四种情况中找最大的和

    可以按照x递增的方向,用树状数组保存y前缀时的最大和,这样就可以解决不考虑新增操作2的问题。

    因为每个点对查询的结果都是独立的,因此按时间进行分治

    左半段时间 右半段时间

    calc(l,r)表示解决这段时间内所有的操作1对这段时间内所有的操作2的影响。

    那么可以递归为:

    1. 只考虑左半段时间中的操作1对左半段时间的操作2的影响
    2. 只考虑右半段时间中的操作1对右半段时间的操作2的影响
    3. 处理左半段时间的操作1对右半段时间的操作2的影响

    递归中需要对操作按照x排序,因此时间复杂度是$T(n)=2T(n/2)+mathcal{O}(nlog n)=mathcal{O}(nlog^2 n)$

    由于是递归,所以可以把排序改为归并,去掉多余的$log(n)$,时间复杂度是$T(n)=2T(n/2)+mathcal{O}(n)=mathcal{O}(nlog n)$

    还要注意会不会出现坐标0导致树状树组死循环

    这中间用了很多卡常的办法,比如memset代替for循环复制,因为结构体可能会有对齐的问题,所以用了强制转换指针……

    本来是个例题,结果要卡常,还是厉害

    (KD-Tree以后再看吧……)

    AC代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define REP(i,a,b) for(register int i=(a); i<(b); i++)
    #define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
    using namespace std;
    #define MAXN 1000007
    #define INF 0x3fffffff
    struct node {
    	int x,y,id;bool v;
    	bool operator<(const node &r) const {
    		return x<r.x || (x==r.x && y<r.y);
    	}
    } op[MAXN], bk[MAXN], tm[MAXN]; int opn;
    int ans[MAXN];
    char buf[1<<21], *p1=buf, *p2=buf;
    #define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2?EOF:*p1++)//无聊的读写挂……
    template <class T>
    inline void read(T&x) {
    	x=0; char ch; do ch=gc(); while(ch<=' ');
    	while(ch>' ') {x=x*10+ch-'0'; ch=gc();}
    }
    template <class T, class... A> void read(T&t, A&...a){read(t);read(a...);}
    ///////////////////////////////////////////////////////////////
    int tr[MAXN];
    int maxp;
    inline void cha(int x, int v) {
    	while(x<=maxp) {
    		tr[x] = max(tr[x],v);
    		x+=x&-x;
    	}
    }
    inline int que(int x) {
    	int ans=-INF;
    	while(x>0) {
    		ans = max(ans, tr[x]);
    		x^=x&-x;
    	}
    	return ans;
    }
    ///////////////////////////////////////////////////////////////
    inline void cdqdiv(int l, int r) {
    	int m=(l+r)>>1;
    	if(l<m) cdqdiv(l,m);
    	if(m+1<r) cdqdiv(m+1,r);
    	int j=l;
    	REPE(i,m+1,r) if(!op[i].v) {
    		for(;j<=m && op[j].x<=op[i].x;j++) if(op[j].v) {
    			cha(op[j].y, op[j].x+op[j].y);
    		}
    		int f=op[i].x+op[i].y-que(op[i].y);
    		ans[op[i].id]=min(ans[op[i].id],f);
    	}
    	REP(i,l,j) if(op[i].v) {
    		int y=op[i].y;
    		for(;y<=maxp;y+=y&-y) tr[y]=-INF;
    	}
    	merge(op+l,op+m+1,op+m+1,op+r+1,tm);
    	memcpy(op+l,tm,(char*)(op+r+1)-(char*)(op+l));
    }
    int main() {
    	int n,m;read(n,m);
    	opn=0;
    	int ids=0; maxp=0;
    	while(n--) {
    		int x,y;read(x,y); x++,y++;
    		maxp=max(maxp,y);
    		op[opn]={.x=x,.y=y,.id=0,.v=true};
    		opn++;
    	}
    	REP(i,0,m) {
    		int v,x,y;read(v,x,y); x++,y++;
    		maxp=max(maxp,y);
    		op[opn]={.x=x,.y=y,.id=(v==1?0:ids++),.v=v==1};
    		opn++;
    	}
    	memcpy(bk,op,(char*)(op+opn)-(char*)op);
    	maxp++;
    	memset(tr,-0x3f,(maxp+1)*sizeof(int));
    	memset(ans,0x3f,ids*sizeof(int));
    	cdqdiv(0,opn-1);
    	
    	memcpy(op,bk,(char*)(op+opn)-(char*)op);
    	REP(i,0,opn) op[i].y=maxp-op[i].y;//避免树状树组查询到负数,在减法的时候可以抵消掉maxp
    	cdqdiv(0,opn-1);
    	
    	memcpy(op,bk,(char*)(op+opn)-(char*)op);
    	REP(i,0,opn) op[i].x=-op[i].x;
    	cdqdiv(0,opn-1);
    	
    	memcpy(op,bk,(char*)(op+opn)-(char*)op);
    	REP(i,0,opn) op[i].x=-op[i].x, op[i].y=maxp-op[i].y;
    	cdqdiv(0,opn-1);
    	
    	REP(i,0,ids) printf("%d
    ", ans[i]);
    }
    
  • 相关阅读:
    循环的注意点
    c语言实践输出某个区间中不是3的倍数的偶数
    while循环for循环优缺点和应用
    while 和do while循环的区别
    多重if else和switch case的区别
    if else的执行流程
    多个if和一个ifelse的区别
    对两个变量排序,从小到大输出
    【译】第四篇 Integration Services:增量加载-Updating Rows
    【译】第三篇 Integration Services:增量加载-Adding Rows
  • 原文地址:https://www.cnblogs.com/sahdsg/p/12264075.html
Copyright © 2020-2023  润新知