日常訓練 腐女的生日 奧妙重重的最短路

題意簡述:平面上給定n 個矩形建築物,問從(0,0) 走到(x0,y0) 的最短距離,只能平行與座標軸行走且不能穿過建築。(n105 ,y  座標[106,106] ,x  座標(0,106]) 保證每個矩形都不相交,且一個矩形的周圍區域不會有別的矩形。
開始做的時候只想到了一個O(n3) 的算法,將每個矩形的四個頂角建點,兩點之間判斷是不是能連邊,結果慢得飛起,n1000  70  分暴力只拿了 30  分。後來討論出好多奧妙重重的性質和解法。
性質1:存在一組解橫座標單調不減(因爲建築都在起點的右側)。
性質2:每個建築可以看成建築左側的擋板,因爲每個矩形周圍區域不會有別的矩形,所以若能貼着擋板左邊走到的地方一定能在原圖中走到。
所以有一種解法是在每條邊的兩個端點外側放置兩個點,每個點向左邊第一個碰到的擋板連邊,邊數和點數一個級別,但由於是網格圖,一開始寫的SPFA硬生生被卡T。

#include<bits/stdc++.h>
#define y1 HA
const int D = 1e6 + 10;
const int A = 2e6 + 30;
const int N = 2e5 + 50;
const int INF = 4e6;
struct P{
    int x, y;
    P(){}
    P(int _x, int _y):
        x(_x),y(_y){}
}p[N];
struct L{
    int x, y1, y2;
}a[N/2];
struct edge{
    int y, v, next;
}mp[N*2];
int x,y,n,cnt,s,first[N],lc[A*2],rc[A*2],tag[A*2],q[N+10],dis[N];
bool inq[N];
bool cmp(const L &a, const L &b){
    return a.x < b.x;
}
void build(int i, int l, int r){
    if (l == r) return;
    tag[i] = -1;
    build(lc[i] = ++cnt,l,(l+r)/2);
    build(rc[i] = ++cnt,(l+r)/2+1,r);
}
void pushdown(int i){
    if (tag[i] == -1) return;
    tag[lc[i]] = tag[rc[i]] = tag[i];
    tag[i] = -1;
}
void chg(int i, int l, int r, int _l, int _r, int c){
    if (l > _r || r < _l) return;
    if (l >= _l && r <= _r) {tag[i] = c; return;}
    pushdown(i);
    chg(lc[i],l,(l+r)/2,_l,_r,c);
    chg(rc[i],(l+r)/2+1,r,_l,_r,c);
}
int qry(int i, int l, int r, int pos){
    if (l == r) return tag[i];
    pushdown(i);
    if (pos <= (l+r)/2) return qry(lc[i],l,(l+r)/2,pos);
    return qry(rc[i],(l+r)/2+1,r,pos);
}
int d(int u, int v){
    return abs(p[u].x - p[v].x) + abs(p[u].y - p[v].y);
}
void ins(int x, int y, int v){
    mp[++s] = (edge){y,v,first[x]};
    first[x] = s;
}
struct rec{
    int x,d;
}heap[N*2],top;
void push(const rec &c){
    heap[++cnt] = c;
    int x = cnt;
    while (x > 1 && heap[x].d < heap[x>>1].d)
        std::swap(heap[x],heap[x>>1]),
        x >>= 1;
};
rec poop(){
    rec ret = heap[1];
    heap[1] = heap[cnt--];
    int x = 1;
    while (x*2<=cnt && heap[x*2].d<heap[x].d || x*2+1<=cnt && heap[x*2+1].d<heap[x].d){
        int e = x * 2 + (x*2+1<=cnt && heap[x*2+1].d<heap[x*2].d);
        std::swap(heap[x],heap[e]);
        x = e;
    }
    return ret;
}
void Dijkstra(){
    n = (n + 1) * 2; cnt = 0;
    for (int i=2; i<=n; i++) dis[i] = INF;
    for (int t=first[1]; t; t=mp[t].next)
        dis[mp[t].y] = mp[t].v,
        push((rec){mp[t].y,dis[mp[t].y]});
    while (cnt){
        for (top = poop(); cnt && dis[top.x] != top.d;top = poop());
        for (int t=first[top.x]; t; t=mp[t].next)
            if (dis[top.x] + mp[t].v < dis[mp[t].y])
                dis[mp[t].y] = dis[top.x] + mp[t].v,
                push((rec){mp[t].y,dis[mp[t].y]});
    }
}
int main(){
    scanf("%d%d%d",&x,&y,&n);
    p[1] = P(0,D);
    p[(n+1)*2] = P(x,y+D);
    for (int i=1; i<=n; i++)
        scanf("%d%d%d%d",&a[i].x,&a[i].y1,&x,&a[i].y2),
        a[i].y1 += D, a[i].y2 += D;
    std::sort(a+1,a+n+1,cmp);
    for (int i=1; i<=n; i++)
        p[i*2  ] = P(a[i].x,a[i].y1-1),
        p[i*2+1] = P(a[i].x,a[i].y2+1);
    build(cnt = 1,1,A);
    for (int i=2; i<=(n+1)*2; i++){
        if (p[i].x >= p[(n+1)*2].x) i = (n+1)*2;
        int q = qry(1,1,A,p[i].y);
        ins(q*2+1,i,d(q*2+1,i));
        if (q) ins(q*2,i,d(q*2,i));
        if (i & 1) chg(1,1,A,a[i>>1].y1,a[i>>1].y2,i>>1);
    }
    Dijkstra();
    printf("%d\n",dis[n]);
    return 0;
}

附上醜陋暴力和醜陋的判斷是否能連邊

#include<bits/stdc++.h>
#define y1 HA
const int N = 4050;
const int INF = 4e6;
struct abc{
    struct P{
    int x, y;
    P(){}
    P(int _x, int _y):
        x(_x),y(_y){}
}a[N];
struct edge{
    int y,v,next;
}mp[N*N];
int n,x,y,cnt,S,T,dis[N],q[N+10],x1[N],x2[N],y1[N],y2[N],first[N],s;
bool inq[N];
};
struct P{
    int x, y;
    P(){}
    P(int _x, int _y):
        x(_x),y(_y){}
}a[N];
struct edge{
    int y,v,next;
}mp[N*N];
int n,x,y,cnt,S,T,dis[N],q[N+10],x1[N],x2[N],y1[N],y2[N],first[N],s;
bool inq[N];
bool range(int a, int x, int y){
    return (a >= x && a <= y) || (a >= y && a <= x);
}
void ins(int x, int y, int v){
    mp[++s] = (edge){y,v,first[x]}; first[x] = s;
    mp[++s] = (edge){x,v,first[y]}; first[y] = s;
}
void SPFA(){
    int head = 1, tail = 2;
    for (int i=1; i<=cnt; i++) dis[i] = INF;
    inq[q[head] = S] = 1;
    dis[S] = 0;
    while (head != tail){
        int x = q[head];
        for (int t=first[x]; t>0; t=mp[t].next)
            if (dis[x] + mp[t].v < dis[mp[t].y]){
                dis[mp[t].y] = dis[x] + mp[t].v;
                if (!inq[mp[t].y]){
                    inq[q[tail++] = mp[t].y] = 1;
                    if (tail > N) tail = 1;
                }
        }
        inq[q[head++]] = 0;
        if (head > N) head = 1;
    }
}
int main(){
    //fprintf(stderr,"%.6f\n",sizeof(abc) * 1.0 / 1024 / 1024);
    //freopen("B.in","r",stdin);
    //freopen("B.out","w",stdout);
    a[S = 1] = P(0,0);
    scanf("%d%d%d",&x,&y,&n);
    a[T = 2] = P(x,y);
    cnt = 2;
    for (int i=1; i<=n; i++){
        scanf("%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i]);
        if (x1[i] > x2[i]) std::swap(x1[i],x2[i]);
        if (y1[i] > y2[i]) std::swap(y1[i],y2[i]);
        a[++cnt] = P(x1[i]-1,y1[i]-1);
        a[++cnt] = P(x1[i]-1,y2[i]+1);
        a[++cnt] = P(x2[i]+1,y1[i]-1);
        a[++cnt] = P(x2[i]+1,y2[i]+1);
    }
    for (int i=1; i<cnt; i++)
        for (int j=i+1; j<=cnt; j++){
            bool xy = 1, yx = 1;
            for (int k=1; k<=n && (xy || yx); k++){
                if (xy && ( (range(a[i].x,x1[k],x2[k]) && (range(y1[k],a[i].y,a[j].y) || range(y2[k],a[i].y,a[j].y)))
                         || (range(a[j].y,y1[k],y2[k]) && (range(x1[k],a[i].x,a[j].x) || range(x2[k],a[i].x,a[j].x))) )) xy = 0;
                if (yx && ( (range(a[j].x,x1[k],x2[k]) && (range(y1[k],a[i].y,a[j].y) || range(y2[k],a[i].y,a[j].y)))
                         || (range(a[i].y,y1[k],y2[k]) && (range(x1[k],a[i].x,a[j].x) || range(x2[k],a[i].x,a[j].x))) )) yx = 0;
            }
            if (xy || yx) ins(i,j,abs(a[i].x-a[j].x) + abs(a[i].y - a[j].y));
        }
    SPFA();
    printf("%d\n",dis[T]);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章