Codeforces 331D
题意
在 \(b*b\) 的平面上有 \(n\) 条有向线段,它们长度 \(≥1\) ,与坐标轴平行,且任意两条互不相交。现在有 \(m\) 个询问,每个询问表示从 \((x,y)\) 开始,初始方向为 \(dir\) ,走 \(t\) 步到达的位置。如果超出平面范围则输出从哪个位置超出的。\((n,m,b\le 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\n",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\n", ans[i][0], ans[i][1]);
return 0;
}