http://codeforces.com/problemset/problem/605/D
题意:
给出n个点, ,你有两个值 ,当一个点的 ,你可以到达这个点,并且 。问到达最后一个点的最短路径。初始时
解析:
将 值离散化作为下标开线段树,每个点将 塞入 点对应的 。
假设我当前在 ,那么我在 的区间集合中,找小于等于 的点,进行更新即可。更新规则使用bfs,保证每个搜到的点都是最短路。所以我们要在找到一个点后从线段树中删除对应的节点。
由于我使用的是pair(second存id),所以找小于等于 的,使用 找到上届之上的位置。
注意线段树子区间和夫区间的删除。
代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define fi first
#define se second
const int maxn=1e5+9;
struct node{
int a,b,c,d,id;
}e[maxn];
int pre[maxn];
int U[maxn*2],num;
#define pill pair<int,int>
set<pill>tr[maxn<<3];
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
void update(int rt,int l,int r,int p,pill val){
tr[rt].insert(val);
if(l==r)return;
if(p<=mid)update(ls,l,mid,p,val);
else update(rs,mid+1,r,p,val);
}
set<pill> query(int rt,int l,int r,int L,int R,pill val){ //val=[b+1,-1]
set<pill>res;
if(l>=L&&r<=R){
if(tr[rt].empty())return res;
auto it=tr[rt].lower_bound(val);
if(it==tr[rt].begin())return res;
auto it2=tr[rt].begin();
while(it2!=it){
res.insert(*it2);
it2++;
}
tr[rt].erase(tr[rt].begin(),it);
if(l!=r&&res.size()){
query(ls,l,mid,L,R,val);
query(rs,mid+1,r,L,R,val);
}
return res;
}
if(L<=mid)res=query(ls,l,mid,L,R,val);
if(R>mid){
auto tmp=query(rs,mid+1,r,L,R,val);
for(auto P:tmp)res.insert(P);
}
for(auto P:res)tr[rt].erase(P);
return res;
}
void bfs(){
queue<pair<int,pill>>Q;
Q.push({lower_bound(U+1,U+1+num,0)-U,{0,-1}}); //a b id
while(!Q.empty()){
auto P=Q.front();
Q.pop();
pill fin={P.se.fi+1,-1};
auto res=query(1,1,num,1,P.fi,fin);
for(auto T:res){
pre[T.se]=P.se.se;
Q.push({e[T.se].c,{e[T.se].d,T.se}});
}
}
}
int main(){
int n;scanf("%d",&n);
rep(i,1,n){
scanf("%d%d%d%d",&e[i].a,&e[i].b,&e[i].c,&e[i].d);
e[i].id=i;
U[++num]=e[i].a;
U[++num]=e[i].c;
}
U[+num]=0;
sort(U+1,U+1+num);
num=unique(U+1,U+1+num)-U-1;
rep(i,1,n){
e[i].a=lower_bound(U+1,U+1+num,e[i].a)-U;
e[i].c=lower_bound(U+1,U+1+num,e[i].c)-U;
}
rep(i,1,n){
update(1,1,num,e[i].a,{e[i].b,e[i].id});
}
bfs();
if(pre[n]==0)return 0*printf("-1\n");
stack<int>S;
int now=n;
do{
S.push(now);
now=pre[now];
}while(now>0);
printf("%d\n",S.size());
while(!S.empty()){
printf("%d ",S.top());S.pop();
}
}