您的位置:首页 > 其它

【NOIP2012提高组】开车旅行

2016-03-18 18:58 525 查看

Description

现在有n个城市,每个城市有它的高度Hi,保证每个Hi互不相同。我们定义两个城市之间的距离dis(i,j)=|Hi−Hj|dis(i,j)=|Hi−Hj|,并且只能从编号小的城市去到编号大的城市。现在有两个人,小A和小B要开车(雾)去旅行。小A先开一天,小B再开一天。每一天都可以从一个开到另一个城市。小A会选择去离当前城市第二近的城市,小B会选择去离当前城市最近的那个城市。如果他们行驶的总路程将会超过给定的X就会不继续开车(∩_∩),结束旅行。求:

1:给定一个X,求从哪一个城市出发,小A行驶的路程/小B行驶的路程最小。(认为一个数/0=∞)。若有多个城市相等,选择高度最高的那个。

2:给出m个询问,每次询问从S出发,限制为X,小A走的路程和小B走的路程

Solution

注意小A和小B开同一辆车,感觉超级坑,TAT

用什么

题目很显然,就是用一个数据结构维护最小值和次小值,可以维护的数据结构有很多啦,这么经典的要求。可以用什么双向链表啊,权值线段树啊(因为下标线段树不容易转移值域,而权值线段树很容易),平衡树啊等等。

怎么做

打个权值线段树练练手,维护这段值域区间的坐标最大值和最小值(权值线段树的经典维护方法)。

为什么两个都要维护呢?

因为,我要在左边找相近的,可能比a[i]小,可能比a[i]大,所以要找a[i]+1到max的坐标小的,和1到a[i]-1找一个大的。一共有四个值,所以排一个序之后,在取前两个,打c++就是好。

然后,因为走得路程在给出的范围下是固定的,所以,可以打经典的倍增算法,像个lca一样。

离散化!

不离散化,要爆啊!!!

开long long啊!

这个吃分啊,吃了70多分。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define ll long long
using namespace std;
const int maxn=100007;
ll i,j,k,l,n,m,x0;
double ans,ans1;
ll a[maxn];
struct node{
int l,r;
}t[maxn*10];
struct noo{
int o,p,q;
}op[maxn*10];
struct nod{
ll a,b;
}pai[maxn*10];
int f[maxn][18];
ll g[maxn][18][2],ans2,xx0,ber,ber1;
ll b[maxn],c[maxn],d[maxn],e[maxn];
void insert(int x,int l,int r,int y){
if(l==r){
t[x].l=t[x].r=l;
}
else{
int mid=(l+r)/2;
if(y<=mid)insert(x*2,l,mid,y);
else insert(x*2+1,mid+1,r,y);
t[x].l=min(t[x*2].l,t[x*2+1].l);
t[x].r=max(t[x*2].r,t[x*2+1].r);
}
}
int dexiao(int x,int l,int r,int y,int z){
if(y>z)return n+1;
if(l==y&&r==z){
return t[x].l;
}
else{
int mid=(l+r)/2;
if(z<=mid)return dexiao(x*2,l,mid,y,z);
else if(y>mid)return dexiao(x*2+1,mid+1,r,y,z);
else{
return min(dexiao(x*2,l,mid,y,mid),dexiao(x*2+1,mid+1,r,mid+1,z));
}
}
}
int deda(int x,int l,int r,int y,int z){
if(y>z)return 0;
if(l==y&&r==z){
return t[x].r;
}
else{
int mid=(l+r)/2;
if(z<=mid)return deda(x*2,l,mid,y,z);
else if(y>mid)return deda(x*2+1,mid+1,r,y,z);
else{
return max(deda(x*2,l,mid,y,mid),deda(x*2+1,mid+1,r,mid+1,z));
}
}
}
void doing(int x,int y){
int i;
ber1=ber=0;
fod(i,17,0){
if(g[x][i][0]+g[x][i][1]<=y){
y-=(g[x][i][0]+g[x][i][1]);
ber=ber+g[x][i][0];ber1=ber1+g[x][i][1];
x=f[x][i];
}
}
if(g[x][0][0]<=y)ber+=g[x][0][0];
}
bool cmp(nod x,nod y){return x.b<y.b||x.b==y.b&&x.a<y.a;}
bool cmp1(noo x,noo y){return x.o<y.o;}
int main(){
scanf("%d",&n);
a[0]=0x7fffffff;
fo(i,1,n){
scanf("%lld",&a[i]);
op[i].o=a[i];op[i].p=i;
}
sort(op+1,op+n+1,cmp1);
fo(i,1,n)d[op[i].p]=i,e[i]=op[i].p;
fo(i,1,n*10)t[i].l=n+1,t[i].r=0;
fod(i,n,1){
pai[1].a=dexiao(1,1,n,d[i]+1,n);
pai[2].a=deda(1,1,n,1,d[i]-1);
pai[3].a=dexiao(1,1,n,pai[1].a+1,n);
pai[4].a=deda(1,1,n,1,pai[2].a-1);
fo(j,1,4)pai[j].b=abs(a[i]-a[e[pai[j].a]]);
sort(pai+1,pai+5,cmp);
if(pai[2].a!=0&&pai[2].a!=1+n)b[i]=e[pai[2].a];
if(pai[1].a!=0&&pai[1].a!=1+n)c[i]=e[pai[1].a];
insert(1,1,n,d[i]);
}
fo(i,1,n){
f[i][0]=c[b[i]];
g[i][0][0]=abs(a[i]-a[b[i]]);
g[i][0][1]=abs(a[b[i]]-a[c[b[i]]]);
}
fo(i,1,17){
fo(j,1,n){
f[j][i]=f[f[j][i-1]][i-1];
g[j][i][0]=g[f[j][i-1]][i-1][0]+g[j][i-1][0];
g[j][i][1]=g[f[j][i-1]][i-1][1]+g[j][i-1][1];

}
}
ans=0x7fffffff;
scanf("%d",&xx0);
fo(i,1,n){
doing(i,xx0);
if(ber1!=0)ans1=ber*1.0/ber1;else ans1=0x7fffffff;
if(ans1<ans||ans1==ans&&a[ans2]<a[i]) ans=ans1,ans2=i;
}
printf("%d\n",ans2);
scanf("%d",&m);
fo(i,1,m){
scanf("%d%d",&k,&l);
ber=ber1=0;
doing(k,l);
printf("%lld %lld\n",ber,ber1);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: