題意 "題目鏈接" 有$n$張牌,每張牌有四個屬性$(a, b, c, d)$,主人公有兩個屬性$(x, y)$(初始時為(0, 0)) 一張牌能夠被使用當且僅當$a define Pair pair define MP(x, y) make_pair(x, y) define fi first d ...
題意
有\(n\)張牌,每張牌有四個屬性\((a, b, c, d)\),主人公有兩個屬性\((x, y)\)(初始時為(0, 0))
一張牌能夠被使用當且僅當\(a < x, b < y\),使用後\(x\)會變為\(c\),\(y\)會變為\(d\)
問使用第\(n\)張牌的最小步數
Sol
直接從\((0, 0)\)開始大力BFS,那麼第一次到達時就是最小的,同時記錄一下前驅
現在的問題就是如何知道哪些點可以選,也就是找到所有\(a < x, b < y\)的點,可以直接樹狀數組+set維護
由於保證了每個元素只出現一次,因此總複雜度為\(O(nlog^2n)\)
#include<bits/stdc++.h>
#define Pair pair<int, int>
#define MP(x, y) make_pair(x, y)
#define fi first
#define se second
#define pb(x) push_back(x)
// #define int long long
#define LL long long
#define pt(x) printf("%d ", x);
#define Fin(x) {freopen(#x".in","r",stdin);}
#define Fout(x) {freopen(#x".out","w",stdout);}
using namespace std;
const int MAXN = 2e5 + 10, INF = 1e9 + 10, mod = 1e9 + 7;
const double eps = 1e-9;
void chmax(int &a, int b) {a = (a > b ? a : b);}
void chmin(int &a, int b) {a = (a < b ? a : b);}
int sqr(int x) {return x * x;}
int add(int x, int y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
void add2(int &x, int y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
int mul(int x, int y) {return 1ll * x * y % mod;}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, a[MAXN], b[MAXN], c[MAXN], d[MAXN], vis[MAXN], dis[MAXN], pre[MAXN], da[MAXN], num;
#define lb(x) (x & (-x))
#define sit set<Pair>::iterator
set<Pair> T[MAXN];
void Add(int x, int v, int id) {
for(; x <= num; x += lb(x)) T[x].insert(MP(v, id));
}
vector<int> Query(int p) {
int x = a[p], y = b[p];
vector<int> res;
for(; x; x -= lb(x)) {
set<Pair> &now = T[x];
while(1) {
sit it = now.lower_bound(MP(y, 0));
if(it == now.end()) break;
res.pb(it -> se); now.erase(it);
}
}
return res;
}
void Des() {
sort(da + 1, da + num + 1); num = unique(da + 1, da + num + 1) - da - 1;
for(int i = 1; i <= N; i++) {
a[i] = num - (lower_bound(da + 1, da + num + 1, a[i]) - da) + 1;
c[i] = num - (lower_bound(da + 1, da + num + 1, c[i]) - da) + 1;
if(i != N) Add(c[i], d[i], i);
}
}
void print(int t) {
printf("%d\n", dis[t]);
for(int u = t; ~u; u = pre[u]) printf("%d ", u);
}
void BFS() {
queue<int> q; q.push(N); pre[N] = -1; dis[N] = 1;
while(!q.empty()) {
int p = q.front(); q.pop();
if(a[p] == num && !b[p]) {print(p); return ;}
vector<int> nxt = Query(p);
for(int i = 0, t; i < nxt.size(); i++) {
if(vis[nxt[i]]) continue; vis[nxt[i]] = 1;
q.push(t = nxt[i]);
dis[t] = dis[p] + 1, pre[t] = p;
}
}
puts("-1");
}
signed main() {
N = read(); bool flag = 0;
for(int i = 1; i <= N; i++) {
a[i] = read(), b[i] = read(), c[i] = read(), d[i] = read();
da[++num] = a[i];
da[++num] = c[i];
flag |= (!a[i] && !b[i]);
}
if(!flag) return puts("-1");
Des();
BFS();
return 0;
}