luogu1081 [NOIp2012]开车旅行 (STL::multiset+倍增)

时间:2023-03-09 08:44:29
luogu1081 [NOIp2012]开车旅行 (STL::multiset+倍增)

先用不管什么方法求出来从每个点出发,A走到哪、B走到哪(我写了一个很沙雕的STL)

然后把每个点拆成两个点,分别表示A从这里出发和B从这里出发,然后连边是要A连到B、B连到A、边长就是这次走的路径长度

为了方便,把不能继续走的点连到一个假节点1上(不连应该也无所谓)

然后我们预处理倍增,但要把A走的距离和B走的距离分开来算

之后就每次往上跳找第一个不能走的地方,然后算一算答案就行了

(整数除整数别忘了先换成double或者乘个1.0.............)

 #include<bits/stdc++.h>
#define pa pair<ll,int>
#define lowb(x) ((x)&(-(x)))
#define REP(i,n0,n) for(i=n0;i<=n;i++)
#define PER(i,n0,n) for(i=n;i>=n0;i--)
#define MAX(a,b) ((a>b)?a:b)
#define MIN(a,b) ((a<b)?a:b)
#define CLR(a,x) memset(a,x,sizeof(a))
#define rei register int
using namespace std;
typedef long long ll;
const int maxn=1e5+,logn=;
const ll inf=1e16; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} int N,M,fa[maxn<<][logn];
ll h[maxn],dis1[maxn<<][logn],dis2[maxn<<][logn];
multiset<pa > st;
bool flag[maxn<<]; void getfa(int x){
flag[x]=;
if(fa[x][]&&!flag[fa[x][]]) getfa(fa[x][]);
for(int i=;fa[x][i-]&&fa[fa[x][i-]][i-];i++){
fa[x][i]=fa[fa[x][i-]][i-];
dis1[x][i]=dis1[x][i-]+dis1[fa[x][i-]][i-];
dis2[x][i]=dis2[x][i-]+dis2[fa[x][i-]][i-];
}
}
void getdis(ll &d1,ll &d2,int x,ll bnd){
d1=d2=;
for(int i=;i>=;i--){
if(fa[x][i]&&dis1[x][i]+dis2[x][i]<=bnd){
bnd-=dis1[x][i]+dis2[x][i];
d1+=dis1[x][i],d2+=dis2[x][i];
x=fa[x][i];
}
}
} int main(){
// freopen("1081.in","r",stdin);
rei i,j,k;
N=rd();
for(i=;i<=N;i++) h[i]=rd();
st.insert(make_pair(inf,));
for(i=N;i;i--){
multiset<pa>::iterator it=st.lower_bound(make_pair(h[i],));
ll mi=inf;int ma=;
if(it->first!=inf)
mi=it->first-h[i],ma=it->second;
if(it!=st.begin()){
it--;
if(h[i]-it->first<=mi) mi=h[i]-it->first,ma=it->second;
}
fa[i<<|][]=ma?(ma<<):;
dis2[i<<|][]=mi; ll mi2=inf;int ma2=;
if(mi!=inf){
it=st.lower_bound(make_pair(h[i]+mi,));
if(it->first!=inf&&it->first==h[i]+mi&&it->second!=ma){
mi2=mi,ma2=it->second;
}else{
if(it->first!=inf&&it->first-h[i]==mi) it++;
if(it->first!=inf&&it->first-h[i]>mi)
mi2=it->first-h[i],ma2=it->second;
it=st.lower_bound(make_pair(h[i]-mi,));
if(it!=st.begin()){
it--;
if(h[i]-it->first>mi&&h[i]-it->first<=mi2)
mi2=h[i]-it->first,ma2=it->second;
}
}
} fa[i<<][]=ma2?(ma2<<|):;
dis1[i<<][]=mi2;
st.insert(make_pair(h[i],i));
// printf("%d %d %lld %d %lld\n",i,fa[i<<1|1][0],mi,fa[i<<1][0],mi2);
}
// for(i=1;i<=(N<<1|1);i++) printf("%d %d\n",i,fa[i][0]);
for(i=;i<=(N<<|);i++) if(!flag[i]) getfa(i);
int x0=rd();
double mm=inf;int mi=;h[]=-inf;
for(i=;i<=N;i++){
ll d1=,d2=;
getdis(d1,d2,i<<,x0);
if(d2==&&mm==inf&&h[mi]<h[i]) mi=i;
else if(d2!=){
double r=1.0*d1/d2;
if(r<mm||(r==mm&&h[mi]<h[i])) mm=r,mi=i;
}
}
printf("%d\n",mi); M=rd();
for(i=;i<=M;i++){
ll d1=,d2=;
int a=rd();ll b=rd();
getdis(d1,d2,a<<,b);
printf("%lld %lld\n",d1,d2);
}
return ;
}