https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=547&page=show_problem&problem=4045
给出一个平面其中某些地方含有倾斜45度的镜子,问激光从左上角水平射入能不能从右下角水平射出,如果不能,在平面某个地方添加一面镜子使得激光可以从右下角水平射出,问有多少地方符合要求。
对于第一问可以通过模拟激光轨迹求得,模拟方法可以通过set的upper_bound实现,具体请看程序。对于第二问,我在手工模拟几副图后发现,可以分别求出从左上水平射入的还有从右下水平射入的两条激光轨迹,如果我们在轨迹交点处放置镜子,则可以满足要求。。之后对于两条轨迹,分别拆成若干横线还有若干竖线,通过离散化用扫描线线段树的方法就可以统计总共交点处。。
下午很快就把程序写完了,比想象中简单很多。。但是犯了一个非常非常2的地方,在扫描线排序的时候竟然没有让添加点排在删除点后面=。=,在某一对点处于同个y坐标时候就悲剧了很久。。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
//By Lin #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<set> #include<vector> #include<map> #include<queue> #define sqr(x) ((x)*(x)) #define Rep(i,n) for(int i = 0; i<n; i++) #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++) #define X first #define Y second #define mp(x,y) make_pair(x,y) using namespace std; typedef long long LL; typedef pair<int,int> pii; #define N 401010 struct Node{ int x,y,d; Node(int _x=0,int _y=0,int _d=0):x(_x),y(_y),d(_d){} }que[2][N]; set<pii> data[2][N]; int R,C,n[2],cnt[2]; int xx[N],yy[N],xcnt,ycnt; pii input[2][N]; LL ans; pii ansp; map<int,int> mx,my; Node nextNode(int x,int y,int d){ set<pii>::iterator iter; if ( d == 0 ){ iter = data[1][y].upper_bound( mp(x,-1) ); if ( data[1][y].size() == 0 || iter == data[1][y].begin() ) return Node(0,y,0); iter--; return Node(iter->X,y,iter->Y?3:1); } else if ( d == 2 ) { iter = data[1][y].upper_bound( mp(x,2) ); if ( iter == data[1][y].end() ) return Node(R+1,y,2); return Node(iter->X,y,iter->Y?1:3); } else if ( d == 1 ) { iter = data[0][x].upper_bound( mp(y,2) ); if ( iter == data[0][x].end() ) return Node(x,C+1,1); return Node(x,iter->X,iter->Y?2:0); } else{ iter = data[0][x].upper_bound( mp(y,-1) ); if ( data[0][x].size() == 0 || iter == data[0][x].begin() ) return Node(x,0,3); iter--; return Node(x,iter->X,iter->Y?0:2); } } bool in_R(int x,int y){ return x>=1 && x<=R && y>=1 && y<=C; } void get_laser(int x,int y,int d,Node que[],int &cnt){ cnt = 1; que[0] = Node(x,y,d); do{ que[cnt] = nextNode(que[cnt-1].x,que[cnt-1].y,que[cnt-1].d); cnt++; }while(in_R(que[cnt-1].x,que[cnt-1].y)); } int num; struct node{ int kind,y,x1,x2; node(){} node(int _k,int _y,int _x1):kind(_k),y(_y),x1(_x1){} node(int _k,int _y,int _x1,int _x2){ kind = _k; y = _y; x1 = min(_x1,_x2)+1; x2 = max(_x1,_x2)-1; } friend bool operator<( const node &a , const node &b){ if ( a.y != b.y ) return a.y < b.y; return a.kind < b.kind; } }op[N*2]; struct Segtree{ int left[N*4],right[N*4],key[N*4]; int L[N*4]; void build(int l,int r,int step){ left[step] = l , right[step] = r; key[step] = 0 ; L[step] = -1; if ( l == r ) return; int mid = (l+r)/2; build(l,mid,step*2); build(mid+1,r,step*2+1); } void updata(int w,int val,int step){ if ( left[step] == right[step] ){ key[step] += val; if ( key[step] ) L[step] = w; else L[step] = -1; return; } int mid = ( left[step] + right[step] )/2; updata( w , val , step*2+(w>mid?1:0) ); key[step] = key[step*2] + key[step*2+1]; L[step] = L[step*2]; if ( L[step] == -1 ) L[step] = L[step*2+1]; } int ask(int l,int r,int &x,int step){ if ( left[step] == l && right[step] == r ){ x = L[step]; return key[step]; } int mid = ( left[step] + right[step] )/2; if ( r <= mid ) return ask(l,r,x,step*2); else if ( mid < l ) return ask(l,r,x,step*2+1); else{ int x1,x2; int ret = ask(l,mid,x,step*2)+ask(mid+1,r,x2,step*2+1); if ( x == -1 ) x = x2; return ret; } } }tree; void ask(int g,int h){ num = 0; Rep(i,cnt[g]-1) if ( que[g][i].x == que[g][i+1].x ){ op[num++] = node( 0 , min(que[g][i].y,que[g][i+1].y)+1, que[g][i].x ); op[num++] = node( 1 , max(que[g][i].y,que[g][i+1].y), que[g][i].x ); } Rep(i,cnt[h]-1) if ( que[h][i].y == que[h][i+1].y ){ if ( abs(que[h][i].x-que[h][i+1].x) <= 1 ) continue; op[num++] = node( 2 , que[h][i].y , que[h][i].x , que[h][i+1].x ); } sort( op , op+num ); tree.build(0,R+1,1); Rep(i,num){ if ( op[i].kind == 0 ) tree.updata( op[i].x1 , 1 , 1 ); if ( op[i].kind == 1 ) tree.updata( op[i].x1 ,-1 , 1 ); if ( op[i].kind == 2 ) { if ( op[i].x1 > op[i].x2 ) continue; int x = -1,k; k = tree.ask( op[i].x1 , op[i].x2,x, 1 ); ans += k; if ( k>0 && (ansp.X == -1 || mp(x,op[i].y) < ansp) ) ansp = mp(x,op[i].y); } } } int main(){ int tt = 0; while ( ~scanf("%d%d%d%d", &R, &C, &n[0], &n[1] ) ) { printf("Case %d: ", ++tt ); xcnt = 0 , ycnt = 0; xx[xcnt++] = 0; yy[ycnt++] = 0; xx[xcnt++] = 1; yy[ycnt++] = 1; xx[xcnt++] = R; yy[ycnt++] = C; Rep(k,2) Rep(i,n[k]){ scanf("%d%d", &input[k][i].X, &input[k][i].Y ); xx[xcnt++] = input[k][i].X; yy[ycnt++] = input[k][i].Y; } sort( xx , xx+xcnt ); R = unique(xx,xx+xcnt)-xx; mx.clear(); Rep(i,R) mx[xx[i]] = i; R--; sort( yy , yy+ycnt ); C = unique(yy,yy+ycnt)-yy; my.clear(); Rep(i,C) my[yy[i]] = i; C--; Rep(i,R+1) data[0][i].clear(); Rep(i,C+1) data[1][i].clear(); Rep(k,2) Rep(i,n[k]){ int x = mx[input[k][i].X] , y = my[input[k][i].Y]; data[0][x].insert( mp(y,k) ); data[1][y].insert( mp(x,k) ); } get_laser(1,0,1,que[0],cnt[0]); if ( que[0][cnt[0]-1].x == R && que[0][cnt[0]-1].y == C+1 ){ printf("0\n"); continue; } get_laser(R,C+1,3,que[1],cnt[1]); ans = 0; ansp = mp(-1,-1); ask(0,1); ask(1,0); if ( ans ) printf("%lld %d %d\n" , ans , xx[ansp.X] , yy[ansp.Y] ); else printf("impossible\n"); } return 0; }