Codeforces 331D

题意

(b*b) 的平面上有 (n) 条有向线段,它们长度 (≥1) ,与坐标轴平行,且任意两条互不相交。现在有 (m) 个询问,每个询问表示从 ((x,y)) 开始,初始方向为 (dir) ,走 (t) 步到达的位置。如果超出平面范围则输出从哪个位置超出的。((n,m,ble 10^5))

Examples

Input
3 3
0 0 0 1
0 2 2 2
3 3 2 3
12
0 0 L 0
0 0 L 1
0 0 L 2
0 0 L 3
0 0 L 4
0 0 L 5
0 0 L 6
2 0 U 2
2 0 U 3
3 0 U 5
1 3 D 2
1 3 R 2
Output
0 0
0 1
0 2
1 2
2 2
3 2
3 2
2 2
3 2
1 3
2 2
1 3

首先以每条线段为节点建一张图,用线段树扫描线维护。
然后我们发现这是一棵基环内向树(每个节点只有一条出边)。
于是对于每个节点搞倍增,询问时倍增即可。
但是询问要离线,原因是你得在搞线段树的同时把每个询问从图的哪个节点开始先弄出来。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long D;
const int maxn=100003,maxlog=53;
const D INFll=4000000000000000000ll;
struct edge{int to,next,w;}e[maxn<<1];
int head[maxn],cnte;
void add(int u,int v,int w){e[++cnte].to=v,e[cnte].w=w,e[cnte].next=head[u],head[u]=cnte;}
struct node{int num,z;}t[maxn<<2];
void pushdown(int p,int l,int r){
	if(l==r)return;
	if(t[p].z){
		t[p<<1].num=t[p<<1|1].num=t[p<<1].z=t[p<<1|1].z=t[p].z;
		t[p].z=0;
	}
}
void build(int p,int l,int r){
	t[p].num=t[p].z=0;
	if(l==r)return;
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
}
void change(int p,int l,int r,int seg_l,int seg_r,int k){
	pushdown(p,l,r);
	if(seg_l<=l&&r<=seg_r){
		t[p].num=t[p].z=k;
		return;
	}
	int mid=(l+r)>>1;
	if(seg_l<=mid)change(p<<1,l,mid,seg_l,seg_r,k);
	if(seg_r>mid)change(p<<1|1,mid+1,r,seg_l,seg_r,k);
}
int query(int p,int l,int r,int pos){
	pushdown(p,l,r);
	if(l==r)return t[p].num;
	int mid=(l+r)>>1;
	if(pos<=mid)return query(p<<1,l,mid,pos);
	else return query(p<<1|1,mid+1,r,pos);
}
struct segment{int x1,y1,x2,y2,num;}a[maxn];
struct QQ{int x,y,aim,num,dir;D t;}b[maxn];
int n,m,k,fa[maxn][maxlog],ans[maxn][2];
D cost[maxn][maxlog];
char mo[2];
int DIR(segment p){return p.x1==p.x2?(p.y1<p.y2?1:3):(p.x1<p.x2?0:2);}
int dist(int x1,int y1,int x2,int y2){return abs(x1-x2)+abs(y1-y2);}
int DIST(int x,int y,segment p){
	if(x>=min(p.x1,p.x2)&&x<=max(p.x1,p.x2)&&y>=min(p.y1,p.y2)&&y<=max(p.y1,p.y2))return 0;
	return x>=min(p.x1,p.x2)&&x<=max(p.x1,p.x2)?min(abs(y-p.y1),abs(y-p.y2)):min(abs(x-p.x1),abs(x-p.x2));
}
pair<int,int> MAP(int x,int y,segment p){
	if(x>=min(p.x1,p.x2)&&x<=max(p.x1,p.x2)&&y>=min(p.y1,p.y2)&&y<=max(p.y1,p.y2))return make_pair(x,y);
	return x>=min(p.x1,p.x2)&&x<=max(p.x1,p.x2)?
		make_pair(x,abs(y-p.y1)<abs(y-p.y2)?p.y1:p.y2):
		make_pair(abs(x-p.x1)<abs(x-p.x2)?p.x1:p.x2,y);
}
void initgraph(){
	build(1,0,k);
	sort(a+1,a+n+1,[](segment p,segment q){return min(p.y1,p.y2)<min(q.y1,q.y2);});
	sort(b+1,b+m+1,[](QQ p,QQ q){return p.y<q.y;});
	int j=1;
	for(int i=1;i<=n;i++){
		for(;j<=m&&b[j].y<min(a[i].y1,a[i].y2);j++)if(b[j].dir==3)b[j].aim=a[query(1,0,k,b[j].x)].num;
		if(a[i].x1==a[i].x2&&a[i].y1>a[i].y2){
			int v=query(1,0,k,a[i].x1);
			if(v)add(a[i].num,a[v].num,dist(a[i].x2,a[i].y2,a[v].x2,a[v].y2));
		}
		else{
			change(1,0,k,min(a[i].x1,a[i].x2),max(a[i].x1,a[i].x2),i);
		}
	}
	for(;j<=m;j++)if(b[j].dir==3)b[j].aim=a[query(1,0,k,b[j].x)].num;

	build(1,0,k);
	sort(a+1,a+n+1,[](segment p,segment q){return max(p.y1,p.y2)>max(q.y1,q.y2);});
	sort(b+1,b+m+1,[](QQ p,QQ q){return p.y>q.y;});
	j=1;
	for(int i=1;i<=n;i++){
		for(;j<=m&&b[j].y>max(a[i].y1,a[i].y2);j++)if(b[j].dir==1)b[j].aim=a[query(1,0,k,b[j].x)].num;
		if(a[i].x1==a[i].x2&&a[i].y1<a[i].y2){
			int v=query(1,0,k,a[i].x1);
			if(v)add(a[i].num,a[v].num,dist(a[i].x2,a[i].y2,a[v].x2,a[v].y2));
		}
		else{
			change(1,0,k,min(a[i].x1,a[i].x2),max(a[i].x1,a[i].x2),i);
		}
	}
	for(;j<=m;j++)if(b[j].dir==1)b[j].aim=a[query(1,0,k,b[j].x)].num;

	build(1,0,k);
	sort(a+1,a+n+1,[](segment p,segment q){return max(p.x1,p.x2)>max(q.x1,q.x2);});
	sort(b+1,b+m+1,[](QQ p,QQ q){return p.x>q.x;});
	j=1;
	for(int i=1;i<=n;i++){
		for(;j<=m&&b[j].x>max(a[i].x1,a[i].x2);j++)if(b[j].dir==0)b[j].aim=a[query(1,0,k,b[j].y)].num;
		if(a[i].y1==a[i].y2&&a[i].x1<a[i].x2){
			int v=query(1,0,k,a[i].y1);
			if(v)add(a[i].num,a[v].num,dist(a[i].x2,a[i].y2,a[v].x2,a[v].y2));
		}
		else{
			change(1,0,k,min(a[i].y1,a[i].y2),max(a[i].y1,a[i].y2),i);
		}
	}
	for(;j<=m;j++)if(b[j].dir==0)b[j].aim=a[query(1,0,k,b[j].y)].num;

	build(1,0,k);
	sort(a+1,a+n+1,[](segment p,segment q){return min(p.x1,p.x2)<min(q.x1,q.x2);});
	sort(b+1,b+m+1,[](QQ p,QQ q){return p.x<q.x;});
	j=1;
	for(int i=1;i<=n;i++){
		for(;j<=m&&b[j].x<min(a[i].x1,a[i].x2);j++)if(b[j].dir==2)b[j].aim=a[query(1,0,k,b[j].y)].num;
		if(a[i].y1==a[i].y2&&a[i].x1>a[i].x2){
			int v=query(1,0,k,a[i].y1);
			if(v)add(a[i].num,a[v].num,dist(a[i].x2,a[i].y2,a[v].x2,a[v].y2));
		}
		else{
			change(1,0,k,min(a[i].y1,a[i].y2),max(a[i].y1,a[i].y2),i);
		}
	}
	for(;j<=m;j++)if(b[j].dir==2)b[j].aim=a[query(1,0,k,b[j].y)].num;
}
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
		a[i].num=i;
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d%s%lld",&b[i].x,&b[i].y,mo,&b[i].t);
		b[i].num=i,b[i].dir=(*mo=='R'?0:(*mo=='U'?1:(*mo=='L'?2:3)));
	}
	initgraph();
	sort(a+1,a+n+1,[](segment p,segment q){return p.num<q.num;});
	for(int i=1;i<=n;i++){
		if(head[i])fa[i][0]=e[head[i]].to,cost[i][0]=e[head[i]].w;
		else cost[i][0]=INFll;
	}
	for(int j=1;j<=50;j++){
		for(int i=1;i<=n;i++){
			fa[i][j]=fa[fa[i][j-1]][j-1];
			cost[i][j]=cost[i][j-1]+cost[fa[i][j-1]][j-1];
			if(cost[i][j]>INFll)cost[i][j]=INFll;
		}
	}
	for(int i=1;i<=m;i++){
		int s=b[i].aim,&X=ans[b[i].num][0],&Y=ans[b[i].num][1];
		if(s){
			if(b[i].t>dist(b[i].x,b[i].y,a[s].x2,a[s].y2)){
				b[i].t-=dist(b[i].x,b[i].y,a[s].x2,a[s].y2);
				for(int j=50;j>=0&&b[i].t>0;j--){
					if(b[i].t>=cost[s][j])b[i].t-=cost[s][j],s=fa[s][j];
				}
				b[i].x=a[s].x2,b[i].y=a[s].y2,b[i].dir=DIR(a[s]),s=fa[s][0];
			}
			if(s&&b[i].t>DIST(b[i].x,b[i].y,a[s])){
				pair<int,int> mp=MAP(b[i].x,b[i].y,a[s]);
				b[i].t-=DIST(b[i].x,b[i].y,a[s]),b[i].x=mp.first,b[i].y=mp.second,b[i].dir=DIR(a[s]);
			}
		}
		switch(b[i].dir){
			case 0:X=min(b[i].x+b[i].t,D(k)),Y=b[i].y;break;
			case 1:X=b[i].x,Y=min(b[i].y+b[i].t,D(k));break;
			case 2:X=max(b[i].x-b[i].t,0ll),Y=b[i].y;break;
			case 3:X=b[i].x,Y=max(b[i].y-b[i].t,0ll);break;
		}
	}
	for(int i=1;i<=m;i++)printf("%d %d
",ans[i][0],ans[i][1]);
	return 0;
}

格式化:

#include <bits/stdc++.h>
using namespace std;
typedef long long D;
const int maxn = 100003, maxlog = 53;
const D INFll = 4000000000000000000ll;
struct edge
{
	int to, next, w;
} e[maxn << 1];
int head[maxn], cnte;
void add(int u, int v, int w) { e[++cnte].to = v, e[cnte].w = w, e[cnte].next = head[u], head[u] = cnte; }
struct node
{
	int num, z;
} t[maxn << 2];
void pushdown(int p, int l, int r)
{
	if (l == r)
		return;
	if (t[p].z)
	{
		t[p << 1].num = t[p << 1 | 1].num = t[p << 1].z = t[p << 1 | 1].z = t[p].z;
		t[p].z = 0;
	}
}
void build(int p, int l, int r)
{
	t[p].num = t[p].z = 0;
	if (l == r)
		return;
	int mid = (l + r) >> 1;
	build(p << 1, l, mid);
	build(p << 1 | 1, mid + 1, r);
}
void change(int p, int l, int r, int seg_l, int seg_r, int k)
{
	pushdown(p, l, r);
	if (seg_l <= l && r <= seg_r)
	{
		t[p].num = t[p].z = k;
		return;
	}
	int mid = (l + r) >> 1;
	if (seg_l <= mid)
		change(p << 1, l, mid, seg_l, seg_r, k);
	if (seg_r > mid)
		change(p << 1 | 1, mid + 1, r, seg_l, seg_r, k);
}
int query(int p, int l, int r, int pos)
{
	pushdown(p, l, r);
	if (l == r)
		return t[p].num;
	int mid = (l + r) >> 1;
	if (pos <= mid)
		return query(p << 1, l, mid, pos);
	else
		return query(p << 1 | 1, mid + 1, r, pos);
}
struct segment
{
	int x1, y1, x2, y2, num;
} a[maxn];
struct QQ
{
	int x, y, aim, num, dir;
	D t;
} b[maxn];
int n, m, k, fa[maxn][maxlog], ans[maxn][2];
D cost[maxn][maxlog];
char mo[2];
int DIR(segment p) { return p.x1 == p.x2 ? (p.y1 < p.y2 ? 1 : 3) : (p.x1 < p.x2 ? 0 : 2); }
int dist(int x1, int y1, int x2, int y2) { return abs(x1 - x2) + abs(y1 - y2); }
int DIST(int x, int y, segment p)
{
	if (x >= min(p.x1, p.x2) && x <= max(p.x1, p.x2) && y >= min(p.y1, p.y2) && y <= max(p.y1, p.y2))
		return 0;
	return x >= min(p.x1, p.x2) && x <= max(p.x1, p.x2) ? min(abs(y - p.y1), abs(y - p.y2)) : min(abs(x - p.x1), abs(x - p.x2));
}
pair<int, int> MAP(int x, int y, segment p)
{
	if (x >= min(p.x1, p.x2) && x <= max(p.x1, p.x2) && y >= min(p.y1, p.y2) && y <= max(p.y1, p.y2))
		return make_pair(x, y);
	return x >= min(p.x1, p.x2) && x <= max(p.x1, p.x2) ? make_pair(x, abs(y - p.y1) < abs(y - p.y2) ? p.y1 : p.y2) : make_pair(abs(x - p.x1) < abs(x - p.x2) ? p.x1 : p.x2, y);
}
void initgraph()
{
	build(1, 0, k);
	sort(a + 1, a + n + 1, [](segment p, segment q) { return min(p.y1, p.y2) < min(q.y1, q.y2); });
	sort(b + 1, b + m + 1, [](QQ p, QQ q) { return p.y < q.y; });
	int j = 1;
	for (int i = 1; i <= n; i++)
	{
		for (; j <= m && b[j].y < min(a[i].y1, a[i].y2); j++)
			if (b[j].dir == 3)
				b[j].aim = a[query(1, 0, k, b[j].x)].num;
		if (a[i].x1 == a[i].x2 && a[i].y1 > a[i].y2)
		{
			int v = query(1, 0, k, a[i].x1);
			if (v)
				add(a[i].num, a[v].num, dist(a[i].x2, a[i].y2, a[v].x2, a[v].y2));
		}
		else
		{
			change(1, 0, k, min(a[i].x1, a[i].x2), max(a[i].x1, a[i].x2), i);
		}
	}
	for (; j <= m; j++)
		if (b[j].dir == 3)
			b[j].aim = a[query(1, 0, k, b[j].x)].num;

	build(1, 0, k);
	sort(a + 1, a + n + 1, [](segment p, segment q) { return max(p.y1, p.y2) > max(q.y1, q.y2); });
	sort(b + 1, b + m + 1, [](QQ p, QQ q) { return p.y > q.y; });
	j = 1;
	for (int i = 1; i <= n; i++)
	{
		for (; j <= m && b[j].y > max(a[i].y1, a[i].y2); j++)
			if (b[j].dir == 1)
				b[j].aim = a[query(1, 0, k, b[j].x)].num;
		if (a[i].x1 == a[i].x2 && a[i].y1 < a[i].y2)
		{
			int v = query(1, 0, k, a[i].x1);
			if (v)
				add(a[i].num, a[v].num, dist(a[i].x2, a[i].y2, a[v].x2, a[v].y2));
		}
		else
		{
			change(1, 0, k, min(a[i].x1, a[i].x2), max(a[i].x1, a[i].x2), i);
		}
	}
	for (; j <= m; j++)
		if (b[j].dir == 1)
			b[j].aim = a[query(1, 0, k, b[j].x)].num;

	build(1, 0, k);
	sort(a + 1, a + n + 1, [](segment p, segment q) { return max(p.x1, p.x2) > max(q.x1, q.x2); });
	sort(b + 1, b + m + 1, [](QQ p, QQ q) { return p.x > q.x; });
	j = 1;
	for (int i = 1; i <= n; i++)
	{
		for (; j <= m && b[j].x > max(a[i].x1, a[i].x2); j++)
			if (b[j].dir == 0)
				b[j].aim = a[query(1, 0, k, b[j].y)].num;
		if (a[i].y1 == a[i].y2 && a[i].x1 < a[i].x2)
		{
			int v = query(1, 0, k, a[i].y1);
			if (v)
				add(a[i].num, a[v].num, dist(a[i].x2, a[i].y2, a[v].x2, a[v].y2));
		}
		else
		{
			change(1, 0, k, min(a[i].y1, a[i].y2), max(a[i].y1, a[i].y2), i);
		}
	}
	for (; j <= m; j++)
		if (b[j].dir == 0)
			b[j].aim = a[query(1, 0, k, b[j].y)].num;

	build(1, 0, k);
	sort(a + 1, a + n + 1, [](segment p, segment q) { return min(p.x1, p.x2) < min(q.x1, q.x2); });
	sort(b + 1, b + m + 1, [](QQ p, QQ q) { return p.x < q.x; });
	j = 1;
	for (int i = 1; i <= n; i++)
	{
		for (; j <= m && b[j].x < min(a[i].x1, a[i].x2); j++)
			if (b[j].dir == 2)
				b[j].aim = a[query(1, 0, k, b[j].y)].num;
		if (a[i].y1 == a[i].y2 && a[i].x1 > a[i].x2)
		{
			int v = query(1, 0, k, a[i].y1);
			if (v)
				add(a[i].num, a[v].num, dist(a[i].x2, a[i].y2, a[v].x2, a[v].y2));
		}
		else
		{
			change(1, 0, k, min(a[i].y1, a[i].y2), max(a[i].y1, a[i].y2), i);
		}
	}
	for (; j <= m; j++)
		if (b[j].dir == 2)
			b[j].aim = a[query(1, 0, k, b[j].y)].num;
}
int main()
{
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d%d%d%d", &a[i].x1, &a[i].y1, &a[i].x2, &a[i].y2);
		a[i].num = i;
	}
	scanf("%d", &m);
	for (int i = 1; i <= m; i++)
	{
		scanf("%d%d%s%lld", &b[i].x, &b[i].y, mo, &b[i].t);
		b[i].num = i, b[i].dir = (*mo == 'R' ? 0 : (*mo == 'U' ? 1 : (*mo == 'L' ? 2 : 3)));
	}
	initgraph();
	sort(a + 1, a + n + 1, [](segment p, segment q) { return p.num < q.num; });
	for (int i = 1; i <= n; i++)
	{
		if (head[i])
			fa[i][0] = e[head[i]].to, cost[i][0] = e[head[i]].w;
		else
			cost[i][0] = INFll;
	}
	for (int j = 1; j <= 50; j++)
	{
		for (int i = 1; i <= n; i++)
		{
			fa[i][j] = fa[fa[i][j - 1]][j - 1];
			cost[i][j] = cost[i][j - 1] + cost[fa[i][j - 1]][j - 1];
			if (cost[i][j] > INFll)
				cost[i][j] = INFll;
		}
	}
	for (int i = 1; i <= m; i++)
	{
		int s = b[i].aim, &X = ans[b[i].num][0], &Y = ans[b[i].num][1];
		if (s)
		{
			if (b[i].t > dist(b[i].x, b[i].y, a[s].x2, a[s].y2))
			{
				b[i].t -= dist(b[i].x, b[i].y, a[s].x2, a[s].y2);
				for (int j = 50; j >= 0 && b[i].t > 0; j--)
				{
					if (b[i].t >= cost[s][j])
						b[i].t -= cost[s][j], s = fa[s][j];
				}
				b[i].x = a[s].x2, b[i].y = a[s].y2, b[i].dir = DIR(a[s]), s = fa[s][0];
			}
			if (s && b[i].t > DIST(b[i].x, b[i].y, a[s]))
			{
				pair<int, int> mp = MAP(b[i].x, b[i].y, a[s]);
				b[i].t -= DIST(b[i].x, b[i].y, a[s]), b[i].x = mp.first, b[i].y = mp.second, b[i].dir = DIR(a[s]);
			}
		}
		switch (b[i].dir)
		{
		case 0:
			X = min(b[i].x + b[i].t, D(k)), Y = b[i].y;
			break;
		case 1:
			X = b[i].x, Y = min(b[i].y + b[i].t, D(k));
			break;
		case 2:
			X = max(b[i].x - b[i].t, 0ll), Y = b[i].y;
			break;
		case 3:
			X = b[i].x, Y = max(b[i].y - b[i].t, 0ll);
			break;
		}
	}
	for (int i = 1; i <= m; i++)
		printf("%d %d
", ans[i][0], ans[i][1]);
	return 0;
}
原文地址:https://www.cnblogs.com/BlogOfchc1234567890/p/10782936.html