605D A. Board Game set+樹狀數組思想

題目鏈接: https://codeforces.com/gym/260204/problem/A

題意:

你現在有 nn 種魔法,每種魔法 ii 都有四個數值 a[i],b[i],c[i],d[i]a[i],b[i],c[i],d[i] , 現在你有初值 x=0,y=0x=0,y=0 ,一個魔法 ii 能被使用當且僅當滿足 a[i]<=x,b[i]<=ya[i]<=x,b[i]<=y 時,並且使用完畢後 x=c[i],y=d[i]x=c[i],y=d[i] 。現在問你最少要用幾個魔法,可以使得魔法 nn 被使用。

做法:

我們將題目的背景看成一個二維的直角座標系,將所有的 a[i],b[i]a[i],b[i] 先畫上去,再將 c[i],d[i]c[i],d[i] 設爲這個點的終點。假設我們到了一個點 c[i],d[i]c[i],d[i] ,那麼以這個點爲右上角, (00)(0,0) 爲左下角的矩形中的未被走過的點都能達到了。

在這裏插入圖片描述

如上圖,原來經過的點如果已經被刪除的話,就不會到達 O(n2)O(n^2) 的複雜度了。

但是這要怎麼存呢(也是在賽上沒想出來的原因),先離散化,再用一個樹狀數組的思想,將點按橫座標向上存,縱座標不變,每個點攜帶的信息除了 b[i]b[i] 之外,還有一個編號,查詢的時候將所有查過的點清除即可。

可能講的有點抽象,可以看看代碼。

代碼

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef pair<int,int> pii;
typedef vector<int> Vi;
const int maxn=100005;
int tmp[maxn<<1],cnt,n,a[maxn],pre[maxn];
int b[maxn],c[maxn],d[maxn],dist[maxn];
set<pii> S[maxn<<1+5];
set<pii>::iterator it,last;
int lowbit(int x){
    return x&(-x);
}
void add(int x,pii p){
    while(x<(maxn<<1)){
        S[x].insert(p);
        x+=lowbit(x);
    }
}
Vi query(int x,int y){
    Vi ret; ret.clear();
    while(x){
        last=S[x].upper_bound({y,maxn});
        for(it=S[x].begin();it!=last;it++){
            ret.push_back(it->second);
        }
        S[x].erase(S[x].begin(),last);
        x-=lowbit(x);
    }
    return ret;
}
void bfs(){
    memset(dist,-1,sizeof(dist));
    memset(pre,-1,sizeof(pre));
    Vi First = query(1,0);
    queue<int> q;
    for(auto x:First) q.push(x),dist[x]=1;
    while(!q.empty()){
        int u=q.front(); q.pop();
        Vi nex=query(c[u],d[u]);
        for(auto v:nex){
            if(dist[v]==-1){
                dist[v]=dist[u]+1;
                pre[v]=u;
                q.push(v);
            }
        }
    }
}
int main(){
    scanf("%d",&n);
    tmp[++cnt]=0;
    rep(i,1,n){
        scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
        tmp[++cnt]=a[i],tmp[++cnt]=c[i];
    }
    sort(tmp+1,tmp+1+cnt);
    cnt=unique(tmp+1,tmp+1+cnt)-tmp-1;
    rep(i,1,n){
        a[i]=lower_bound(tmp+1,tmp+1+cnt,a[i])-tmp;
        c[i]=lower_bound(tmp+1,tmp+1+cnt,c[i])-tmp;
        add(a[i],{b[i],i});
    }
    bfs();
    if(dist[n]==-1) printf("-1\n");
    else{
        stack<int> Sa;
        int now=n;
        while(now!=-1){
            Sa.push(now);
            now=pre[now];
        }
        int sz=Sa.size();
        printf("%d\n",sz);
        for(int i=1;i<=sz;i++){
            printf("%d%c",Sa.top(),i==sz?'\n':' ');
            Sa.pop();
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章