[LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小園丁與老司機

[LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小園丁與老司機

題意

給定平面上的 \(n\) 個整點 \((x_i,y_i)\), 一共有兩個問題.php

第一個問題是從原點 \((0,0)\) 出發, 在只能向←↖↑↗→五個方向中有未到達的點的方向走且在沒有到達一個點的時候不能中途轉彎的狀況下最多能到達的點數, 並輸出一種可行方案.c++

第二個問題是若是用若干能夠從任意點出發可是隻能向↖↑↗方向沿着全部可能出如今最優解的直線上走的壓路機將全部可能出如今最優解上的邊都走過至少一遍所須要的最少的壓路機數量.git

\(n\le 50000,|x_i|\le 10^9,0<y_i\le 10^9\)spa

題解

農業題真tm勁啊rest

第一個問題至關於一個有特殊限制的分層圖最長路.code

顯然走的時候 \(y\) 值是單調不降的, 咱們能夠從小到大枚舉 \(y\) 座標分層計算.blog

同一層的時候假設在 \(s\) 處進入, 從 \(t\) 處離開, 那麼最優策略必定是先走到這一層中對 \(t\) 的對側端點而後再回來. 咱們設 \(f^{[1]}_i\) 爲從原點走到 \(i\) 的最長路, \(f^{[2]}_i\) 爲上一層中能夠走到點 \(i\) 的點中最大的 \(f^{[1]}\), 即進入當前層以前的最長路.get

由於↖↑↗三個方向能移動到的位置分別保持 \(x+y\), \(x\), \(x-y\) 相等, 因而能夠全局維護一個哈希表或者 map 來維護 \(f^{[2]}_i\). 若是之前沒有出現過相等位置則貢獻爲 \(-\infty\). 原點的貢獻爲 \(0\).it

\(f^{[2]}\) 計算 \(f^{[1]}\) 則能夠分類討論, \(s=t\) 時是平凡狀況, 注意這裏到達後這個點會變成已到達的, 若是要訪問同一層的其餘點就會回不來, 因而這裏直接等於 \(f^{[2]}_i+1\). 剩下的狀況一個是 \(s<t\), 一個是 \(s>t\).class

\(s<t\) 的時候能夠訪問到 \(t\) 左側的全部點, \(s>t\) 的時候能夠訪問到 \(t\) 右側的全部點, 顯然這個貢獻和 \(s\) 無關, 正反掃一遍記錄一下先後綴最大的 \(f^{[2]}_i\) 就行了.

以上貢獻的時候都須要維護一個 pair, 第一關鍵字是DP值, 第二關鍵字是來源. 用 pair 能夠節省額外的記錄方案代碼. 注意 \(f^{[1]}_i\) 的來源記錄的是同層的 \(s\) 的位置, \(f^{[2]}_i\) 的來源記錄的是上一層的 \(t\) 的位置.

輸出方案的時候處理一下同一層的特判一下 \(s=t\) 的狀況第一個問題就作完了.

第二個問題依然比較噁心

下界最小流的模型很顯然就不說了. 關鍵在於把這個圖建出來. 由於它問的是全部可能出如今最優解的直線.

若是 \(u\) 沿↖↑↗三個方向能夠到達 \(v\), 那麼只要原點到 \(u\) 的最長路和 \(v\) 出發的最長路之和與第一問的答案相等就能夠出如今最優解上. 那麼就須要計算出從某個點出發的最長路的長度.

這個DP和第一問相似, 再也不贅述. 不過此次能夠在任意位置結束, 因此沒有後繼的時候貢獻是 \(0\) 而不是 \(-\infty\).

最後注意一下不要寫假Dinic...這題數據範圍比較大, 假複雜度的Dinic很容易被卡...我猜Po姐就是由於寫了假Dinic纔沒有阿克Day2的

參考代碼

一杯茶, 一包煙, 一個破題調一天

#include <bits/stdc++.h>

const int MAXV=50010;
const int MAXN=50010;
const int MAXE=1e7+10;
const int INF=0x7FFFFFFF;
typedef std::pair<int,int> Pair;

struct Edge{
    int from;
    int to;
    int flow;
    bool blk;
    Edge* rev;
    Edge* next;
};
Edge E[MAXE];
Edge* head[MAXV];
Edge* cur[MAXV];
Edge* top=E;

int n;
int ycnt;
int s[MAXN];
Pair a[MAXN];
int id[MAXN];
int bk1[MAXN];
int bk2[MAXN];
Pair fw1[MAXN];
Pair fw2[MAXN];
int depth[MAXV];
std::map<int,int> bkX;
std::map<int,int> bkN;  // x+y fixed
std::map<int,int> bkZ;  // x-y fixed
std::map<int,Pair> fwX;
std::map<int,Pair> fwN; // x+y fixed
std::map<int,Pair> fwZ; // x-y fixed
std::vector<Pair> pos[MAXN];
std::pair<Pair,int> P[MAXN];

int ReadInt();
int GetB(int);
Pair GetF(int);
bool BFS(int,int);
int Dinic(int,int);
int DFS(int,int,int);
void UpdateF(int,int);
void UpdateB(int,int);
Edge* Insert(int,int,int);

int main(){
    n=ReadInt();
    for(int i=1;i<=n;i++){
        a[i].first=P[i].first.first=ReadInt();
        s[i]=a[i].second=P[i].first.second=ReadInt();
        P[i].second=i;
    }
    std::sort(s+1,s+n+1);
    std::sort(P+1,P+n+1);
    ycnt=std::unique(s+1,s+n+1)-(s+1);
    for(int i=1;i<=n;i++)
        pos[std::lower_bound(s+1,s+ycnt+1,P[i].first.second)-s].emplace_back(P[i].first.first,P[i].second);
    pos[0].emplace_back(0,0);
    UpdateF(0,0);
    Pair ans;
    for(int i=1;i<=ycnt;i++){
        for(size_t j=0;j<pos[i].size();j++){
            int x=pos[i][j].second;
            auto p=GetF(x);
            fw2[x]=p;
            fw1[x]=Pair(p.first+1,x);
        }
        auto maxf=Pair(INT_MIN,0);
        for(size_t j=0;j<pos[i].size();j++){
            int p=pos[i][j].second;
            id[p]=j;
            fw1[p]=std::max(fw1[p],Pair(maxf.first+j+1,maxf.second));
            if(fw2[p].first>=0)
                maxf=std::max(maxf,Pair(fw2[p].first,p));
        }
        maxf=Pair(INT_MIN,0);
        for(size_t j=pos[i].size()-1;j<pos[i].size();j--){
            int p=pos[i][j].second;
            fw1[p]=std::max(fw1[p],Pair(maxf.first+(pos[i].size()-j),maxf.second));
            if(fw2[p].first>=0)
                maxf=std::max(maxf,Pair(fw2[p].first,p));
            UpdateF(p,fw1[p].first);
            ans=std::max(ans,Pair(fw1[p].first,p));
        }
    }
    int bkans=0;
    for(int i=ycnt;i>=1;i--){
        for(size_t j=0;j<pos[i].size();j++){
            int x=pos[i][j].second;
            bk2[x]=GetB(x);
            bk1[x]=bk2[x]+1;
        }
        int maxb=0;
        for(size_t j=0;j<pos[i].size();j++){
            int p=pos[i][j].second;
            bk1[p]=std::max(bk1[p],maxb);
            maxb=std::max(maxb,int(bk2[p]+(pos[i].size()-j)));
        }
        maxb=0;
        for(size_t j=pos[i].size()-1;j<pos[i].size();j--){
            int p=pos[i][j].second;
            bk1[p]=std::max(bk1[p],maxb);
            maxb=std::max(maxb,int(bk2[p]+j+1));
            UpdateB(p,bk1[p]);
            bkans=std::max(bkans,bk1[p]);
        }
    }
    printf("%d\n",ans.first);
    std::vector<int> sol;
    for(int cur=ans.second;cur!=0;){
        sol.push_back(cur);
        int i=std::lower_bound(s+1,s+ycnt+1,a[cur].second)-s;
        if(fw1[cur].second!=cur){
            int next=fw1[cur].second;
            if(id[next]<id[cur]){
                for(int j=id[cur]-1;j>id[next];j--)
                    sol.push_back(pos[i][j].second);
                for(int j=0;j<=id[next];j++)
                    sol.push_back(pos[i][j].second);
            }
            else{
                for(int j=id[cur]+1;j<id[next];j++)
                    sol.push_back(pos[i][j].second);
                for(int j=pos[i].size()-1;j>=id[next];j--)
                    sol.push_back(pos[i][j].second);
            }
            cur=fw1[cur].second;
        }
        cur=fw2[cur].second;
    }
    for(int i=ans.first-1;i>=0;i--)
        printf("%d%c",sol[i]," \n"[i==0]);
    bkX.clear();
    bkN.clear();
    bkZ.clear();
    int ss=n+1,tt=n+2,s=n+3,t=n+4;
    Edge* Ex;
    std::vector<Edge*> aux;
    aux.push_back(Ex=Insert(t,s,INF));
    for(int i=0;i<=n;i++){
        Insert(s,i,INF);
        Insert(i,t,INF);
    }
    auto check=[=,&aux](int r,int k){
        if(fw1[r].first+bk1[k]==ans.first){
            Insert(r,k,INF);
            aux.push_back(Insert(ss,k,1));
            aux.push_back(Insert(r,tt,1));
        }
    };
    for(int i=ycnt;i>=0;i--){
        for(auto p:pos[i]){
            int x,y,r=p.second;
            std::tie(x,y)=a[r];
            if(bkX.count(x))
                check(r,bkX[x]);
            if(bkN.count(x+y))
                check(r,bkN[x+y]);
            if(bkZ.count(x-y))
                check(r,bkZ[x-y]);
            bkX[x]=r;
            bkN[x+y]=r;
            bkZ[x-y]=r;
        }
    }
    Dinic(ss,tt);
    for(auto p:aux)
        p->blk=p->rev->blk=true;
    int flow=Ex->rev->flow;
    flow-=Dinic(t,s);
    printf("%d\n",flow);
    return 0;
}

int GetB(int i){
    int ans=0;
    int x=a[i].first;
    int y=a[i].second;
    if(bkX.count(x))
        ans=std::max(ans,bkX[x]);
    if(bkN.count(x+y))
        ans=std::max(ans,bkN[x+y]);
    if(bkZ.count(x-y))
        ans=std::max(ans,bkZ[x-y]);
    return ans;
}

void UpdateB(int i,int d){
    if(d<0)
        return;
    int x=a[i].first;
    int y=a[i].second;
    auto f=[](int& x,int d){x=std::max(x,d);};
    f(bkX[x],d);
    f(bkN[x+y],d);
    f(bkZ[x-y],d);
}

Pair GetF(int i){
    int x=a[i].first;
    int y=a[i].second;
    Pair ans(INT_MIN,0);
    if(fwX.count(x))
        ans=std::max(ans,fwX[x]);
    if(fwN.count(x+y))
        ans=std::max(ans,fwN[x+y]);
    if(fwZ.count(x-y))
        ans=std::max(ans,fwZ[x-y]);
    return ans;
}

void UpdateF(int i,int d){
    if(d<0)
        return;
    int x=a[i].first;
    int y=a[i].second;
    auto p=Pair(d,i);
    auto f=[](Pair& x,Pair d){x=std::max(x,d);};
    f(fwX[x],p);
    f(fwN[x+y],p);
    f(fwZ[x-y],p);
}

int Dinic(int s,int t){
    int ans=0;
    while(BFS(s,t))
        ans+=DFS(s,INF,t);
    return ans;
}

bool BFS(int s,int t){
    memset(depth,0,sizeof(depth));
    std::queue<int> q;
    cur[s]=head[s];
    depth[s]=1;
    q.push(s);
    while(!q.empty()){
        s=q.front();
        q.pop();
        for(Edge* i=head[s];i!=NULL;i=i->next){
            if(!i->blk&&i->flow>0&&depth[i->to]==0){
                depth[i->to]=depth[s]+1;
                cur[i->to]=head[i->to];
                if(i->to==t)
                    return true;
                q.push(i->to);
            }
        }
    }
    return false;
}

int DFS(int s,int flow,int t){
    if(s==t||flow<=0)
        return flow;
    int rest=flow;
    for(Edge*& i=cur[s];i!=NULL;i=i->next){
        if(!i->blk&&i->flow>0&&depth[i->to]==depth[s]+1){
            int tmp=DFS(i->to,std::min(rest,i->flow),t);
            if(tmp<=0)
                depth[i->to]=0;
            rest-=tmp;
            i->flow-=tmp;
            i->rev->flow+=tmp;
            if(rest<=0)
                break;
        }
    }
    return flow-rest;
}

inline Edge* Insert(int from,int to,int flow){
    Edge* ret=top;
    top->from=from;
    top->to=to;
    top->flow=flow;
    top->blk=false;
    top->rev=top+1;
    top->next=head[from];
    head[from]=top++;

    top->from=to;
    top->to=from;
    top->flow=0;
    top->blk=false;
    top->rev=top-1;
    top->next=head[to];
    head[to]=top++;
    return ret;
}

inline int ReadInt(){
    int x=0;
    int sgn=1;
    register char ch=getchar();
    while(!isdigit(ch)){
        sgn=(ch=='-'?-sgn:sgn);
        ch=getchar();
    }
    while(isdigit(ch)){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*sgn;
}

相關文章
相關標籤/搜索