【datastruct】2012world final i.A Safe Bet

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坐标时候就悲剧了很久。。

View Code
//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;
}

 

posted @ 2013-03-13 16:36  lzqxh  阅读(286)  评论(0编辑  收藏  举报