codeforces 331D3 Escaping on Beaveractor - 线段树 - 扫描线 - 倍增

传送门:http://codeforces.com/contest/331/problem/D3

第一篇blog送给这道折磨我一上午的码农题。

题目大意很简单:b*b的平面上有n条互不相交且平行于坐标轴的有向线段,运动到线段上之后运动方向会改变成沿着线段的方向。

有q组询问,每组给出起始坐标,出发方向和运动距离,求最后停在哪个位置。如果中途会离开平面范围内就输出从哪个位置离开的。

一个自然的想法是:把询问离线,考虑计算从每条线段的终点以及每组询问的起点出发,下一次拐弯是在哪里。

我们可以将4个方向分开做,对于一个方向,我们把所有线段及询问按照这个方向排序(如方向为向右,则按照x坐标从大到小排序),用扫描线进行处理:扫到一条线段时,将它覆盖的区间插入线段树,计算答案时直接查询即可。

把这个拐弯关系建成图,由于一个点只会有1条出边,所以图会是个内向基环树森林,可以直接倍增预处理。

当然这个题细节很多:

怎么处理一条路径在某条线段的中间拐弯?我们可以在拐弯处插入一个新节点。

对于离开平面的情况,在离开平面处建一个点,并把它的出边指向自己。

还要注意一点:虽然保证线段不相交,但并不保证询问的起点不在线段上,因此这里要小心地特判。

4遍线段树+大量的细节特判让这个题很考验代码能力,我折腾了一上午,写代码1.5h+调试约1h,最后码长6.2k。

总结:一道不可多得的集思维难度代码难度为一体的好题。

(感谢可爱的kevinshuai小学妹Mys_C_K的安利)

#include<bits/stdc++.h>
using namespace std;
#define li long long
#define gc getchar()
#define pc putchar
li read(){
	li x = 0,c = gc;
	while(!isdigit(c)) c = gc;
	while(isdigit(c)){
		x = (x << 1) + (x << 3) + (c ^ '0');
		c = gc;
	}
	return x;
}
void print(li q){
	if(q >= 10) print(q / 10);
	pc(q % 10 + '0');
}
int n,s,m;
struct jt{
	int xa,ya,xb,yb,p,id;
	int mxx,mxy,mnx,mny;
	bool fg;
}a[500010],d[500010];
int asx[100010],asy[100010];
struct qy{
	int x,y,p;
	li t;
}b[100010];
int tot;
//D 0
//R 1
//U 2
//L 3
inline bool cp0(jt q,jt w){return q.mny == w.mny ? q.fg < w.fg : q.mny < w.mny;}
inline bool cp1(jt q,jt w){return q.mxx == w.mxx ? q.fg < w.fg : q.mxx > w.mxx;}
inline bool cp2(jt q,jt w){return q.mxy == w.mxy ? q.fg < w.fg : q.mxy > w.mxy;}
inline bool cp3(jt q,jt w){return q.mnx == w.mnx ? q.fg < w.fg : q.mnx < w.mnx;}
int t[500010];
#define ls q << 1
#define rs q << 1 | 1
#define ln ls,l,mid
#define rn rs,mid + 1,r
#define md int mid = l + r >> 1
void init(int q,int l,int r){
	t[q] = -1;
	if(l == r) return;
	md;
	init(ln);init(rn);
}
inline void ps(int q){
	if(t[q] == -1) return;
	t[ls] = t[rs] = t[q];t[q] = -1;
}
void xg(int q,int l,int r,int al,int ar,int x){
	if(l >= al && r <= ar){
		t[q] = x;
		return;
	}
	ps(q);
	md;
	if(mid >= al) xg(ln,al,ar,x);
	if(mid < ar) xg(rn,al,ar,x);
}
int cx(int q,int l,int r,int x){
	if(l == r) return t[q];
	ps(q);
	md;
	if(mid >= x) return cx(ln,x);
	return cx(rn,x);
}
int s1[62][500010];
li s2[62][500010];
inline void ins(int u,int v,int w){s1[0][u] = v;s2[0][u] = w;}
inline void buildst(){
	register int i,j;
	for(i = 1;i <= 60;++i){
		for(j = 1;j <= tot;++j){
			s1[i][j] = s1[i - 1][s1[i - 1][j]];
			s2[i][j] = s2[i - 1][j] + s2[i - 1][s1[i - 1][j]];
			if(s2[i][j] > 1e18) s2[i][j] = 2e18;
		}
	} 
}
void file(){
	freopen("331d3.in","r",stdin);
	freopen("331d3.out","w",stdout);
}
int main(){
	//file();
	int i,j,u;
	char c;
	n = read();s = read();
	for(i = 1;i <= n;++i){
		a[i].xa = read();a[i].ya = read();a[i].xb = read();a[i].yb = read();
		if(a[i].xa == a[i].xb && a[i].ya == a[i].yb){
			--n;--i;continue;
		}
		if(a[i].xa == a[i].xb){
			if(a[i].ya < a[i].yb) a[i].p = 2; 
			else a[i].p = 0;
		}
		else{
			if(a[i].xa < a[i].xb) a[i].p = 1;
			else a[i].p = 3; 
		}
		a[i].id = i;
	}
	m = read();tot = n + m;
	for(i = 1;i <= m;++i){
		b[i].x = read();b[i].y = read();c = gc;while(c < 'A' || c > 'Z') c = gc;b[i].t = read();
		b[i].p = c == 'D' ? 0 : c == 'R' ? 1 : c == 'U'? 2 : 3;
		a[i + n].xa = a[i + n].xb = b[i].x;a[i + n].ya = a[i + n].yb = b[i].y;a[i + n].id = i + n;a[i + n].p = b[i].p;a[i + n].fg = 1;
	}
	for(i = 1;i <= n + m;++i){
		a[i].mxx = max(a[i].xa,a[i].xb);a[i].mnx = min(a[i].xa,a[i].xb);
		a[i].mxy = max(a[i].ya,a[i].yb);a[i].mny = min(a[i].ya,a[i].yb);
	}
	#define x1 xa
	#define y1 ya
	#define x2 xb
	#define y2 yb
	//D 0
	sort(a + 1,a + n + m + 1,cp0);
	init(1,0,s);
	for(i = 1;i <= n + m;++i){
		if(!a[i].fg){
			if(a[i].p != 0) xg(1,0,s,a[i].mnx,a[i].mxx,i);
		}
		if(a[i].p == 0){
			u = cx(1,0,s,a[i].mxx);
			a[++tot].x1 = a[i].mxx;a[tot].id = tot;
			if(u == -1){
				a[tot].y1 = 0;
				ins(a[i].id,tot,a[i].mny);
				ins(tot,tot,0);
			}
			else{
				if(a[u].p == 2){
					a[tot].y1 = min(a[i].mny,a[u].mxy);
					ins(tot,a[u].id,a[u].mxy - a[tot].y1);
				}
				else{
					a[tot].y1 = a[u].mxy;
					ins(tot,a[u].id,abs(a[u].x2 - a[tot].x1));
				}
				ins(a[i].id,tot,a[i].mny - a[tot].y1);
			}
		}
	}
	//R 1
	sort(a + 1,a + n + m + 1,cp1);
	init(1,0,s);
	for(i = 1;i <= n + m;++i){
		if(!a[i].fg){
			if(a[i].p != 1) xg(1,0,s,a[i].mny,a[i].mxy,i);
		}
		if(a[i].p == 1){
			u = cx(1,0,s,a[i].mxy);
			a[++tot].y1 = a[i].mxy;a[tot].id = tot;
			if(u == -1){
				a[tot].x1 = s;
				ins(a[i].id,tot,s - a[i].mxx);
				ins(tot,tot,0);
			}
			else{
				if(a[u].p == 3){
					a[tot].x1 = max(a[i].mxx,a[u].mnx);
					ins(tot,a[u].id,a[tot].x1 - a[u].mnx);
				}
				else{
					a[tot].x1 = a[u].mxx;
					ins(tot,a[u].id,abs(a[u].y2 - a[tot].y1));
				}
				ins(a[i].id,tot,a[tot].x1 - a[i].mxx);
			}
		}
	}
	//U 2
	sort(a + 1,a + n + m + 1,cp2);
	init(1,0,s);
	for(i = 1;i <= n + m;++i){
		if(!a[i].fg){
			if(a[i].p != 2) xg(1,0,s,a[i].mnx,a[i].mxx,i);
		}
		if(a[i].p == 2){
			u = cx(1,0,s,a[i].mxx);
			a[++tot].x1 = a[i].mxx;a[tot].id = tot;
			if(u == -1){
				a[tot].y1 = s;
				ins(a[i].id,tot,s - a[i].mxy);
				ins(tot,tot,0);
			}
			else{
				if(a[u].p == 0){
					a[tot].y1 = max(a[i].mxy,a[u].mny);
					ins(tot,a[u].id,a[tot].y1 - a[u].mny);
				}
				else{
					a[tot].y1 = a[u].mxy;
					ins(tot,a[u].id,abs(a[u].x2 - a[tot].x1));
				}
				ins(a[i].id,tot,a[tot].y1 - a[i].mxy);
			}
		}
	}
	//L 3
	sort(a + 1,a + n + m + 1,cp3);
	init(1,0,s);
	for(i = 1;i <= n + m;++i){
		if(!a[i].fg){
			if(a[i].p != 3) xg(1,0,s,a[i].mny,a[i].mxy,i);
		}
		if(a[i].p == 3){
			u = cx(1,0,s,a[i].mxy);
			a[++tot].y1 = a[i].mxy;a[tot].id = tot;
			if(u == -1){
				a[tot].x1 = 0;
				ins(a[i].id,tot,a[i].mnx);
				ins(tot,tot,0);
			}
			else{
				if(a[u].p == 1){
					a[tot].x1 = min(a[i].mnx,a[u].mxx);
					ins(tot,a[u].id,a[u].mxx - a[tot].x1);
				}
				else{
					a[tot].x1 = a[u].mxx;
					ins(tot,a[u].id,abs(a[u].y2 - a[tot].y1));
				}
				ins(a[i].id,tot,a[i].mnx - a[tot].x1);
			}
		}
	}	
	for(i = n + m + 1;i <= tot;++i) a[i].x2 = a[i].x1,a[i].y2 = a[i].y1;
	for(i = 1;i <= tot;++i) d[a[i].id] = a[i];
	buildst();
	li nw,lft;
	for(i = 1;i <= tot;++i) if(d[i].fg){
		nw = i;lft = b[d[i].id - n].t;
		for(j = 60;j >= 0;--j) if(lft >= s2[j][nw]){
			lft -= s2[j][nw];
			nw = s1[j][nw];
		}
		asx[d[i].id - n] = d[nw].x2;asy[d[i].id - n] = d[nw].y2;
		if(s1[0][nw] != nw){
			if(d[s1[0][nw]].x2 > d[nw].x2) asx[d[i].id - n] += lft;
			else if(d[s1[0][nw]].x2 < d[nw].x2) asx[d[i].id - n] -= lft;
			else if(d[s1[0][nw]].y2 > d[nw].y2) asy[d[i].id - n] += lft;
			else if(d[s1[0][nw]].y2 < d[nw].y2) asy[d[i].id - n] -= lft; 
		}
	}
	for(i = 1;i <= m;++i) print(asx[i]),pc(' '),print(asy[i]),pc('\n');
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值