#Problem
偷个懒一定不会被发现的
#题外话
话说上午才考完令人发指的**[真·NOIp膜你赛]**,然后整个人都不好了,而且这道题目还是从昨天晚上调一直调到今天下午才A的,然而dalao们都是1A。尤其是中间在调试的时候,内心已经爆炸了。
注 : N O I p 指 N O I p l u s / N O I p r o f e s s i o n a l 注:NOIp指NOIplus/NOIprofessional 注:NOIp指NOIplus/NOIprofessional
#Solution
其实我觉得当年NOIP出这道题还是比较良心的,暴力分有70分,也就是说单纯去模拟就有70分诶,所以打暴力的性价比是很高的!尤其在考试的时候,我肯定不会优先打这道题的正解,除非你有像 @kb 一样深厚的功力。
很明显,如果打单纯的模拟是拿不了满分的,但是看看数据范围,我们会发现只需要一个log级别的优化就可以A了,那么很容易想到用倍增进行优化,令两天为一轮,那么按照轮次来进行倍增,于是就可以预处理出走 2 i 2^i 2i轮之后走到的节点以及小A走的公里数,小B走的公里数。然后按照题意分别枚举即可。但是这道题目还有一个坑点,就是枚举完轮数之后,小A有可能还是可以走,那么在最后的时候还要特判一下。
#Code
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=100010;
struct data{
int l,r,h,id;
bool operator < (const data &x)const {return h<x.h;}
}c[maxn];
ll x;
int n,m,da,db,l,r,t,ans;
double minx=0x3f3f3f3f;
int p[maxn],na[maxn],nb[maxn],a[maxn],b[maxn],f[maxn][21],disa[maxn][21],disb[maxn][21];
int abs(int x){return x<0?-x:x;}
void init(int now)
{
int l=c[p[now]].l,r=c[p[now]].r;
if(!r||(l&&c[p[now]].h-c[l].h<=c[r].h-c[p[now]].h))//the left point is near
{
nb[now]=c[l].id;
int ll=c[l].l;
if(!r||(ll&&c[p[now]].h-c[ll].h<=c[r].h-c[p[now]].h))
na[now]=c[ll].id;
else
na[now]=c[r].id;
}
else
{
nb[now]=c[r].id;
int rr=c[r].r;
if(!rr||(l&&c[p[now]].h-c[l].h<=c[rr].h-c[p[now]].h))
na[now]=c[l].id;
else
na[now]=c[rr].id;
}
if(l)
c[l].r=r;
if(r)
c[r].l=l;
}
void prepare()
{
for(int j=1;j<=20;j++)//请注意循环次序!
for(int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
disa[i][j]=disa[i][j-1]+disa[f[i][j-1]][j-1];
disb[i][j]=disb[i][j-1]+disb[f[i][j-1]][j-1];
}
}
void get(ll x,int p)
{
da=db=0;
for(int i=20;i>=0;i--)
if(f[p][i]&&(ll)(da+db+disa[p][i]+disb[p][i])<=x)//为了以防万一
{
da+=disa[p][i];
db+=disb[p][i];
p=f[p][i];
}
if(na[p]&&da+db+disa[p][0]<=x)
da+=disa[p][0];//特判a单独走的情况
}
int main()
{
freopen("in.txt","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&c[i].h);
c[i].id=i;
}
sort(c+1,c+n+1);
for(int i=1;i<=n;i++)
{
p[c[i].id]=i;//可以说类似于一个离散化吧
c[i].l=i-1;c[i].r=i+1;
}
c[1].l=c[n].r=0;
for(int i=1;i<=n;i++)
init(i);
for(int i=1;i<=n;i++)
{
f[i][0]=nb[na[i]];
disa[i][0]=abs(c[p[i]].h-c[p[na[i]]].h);
disb[i][0]=abs(c[p[f[i][0]]].h-c[p[na[i]]].h);
}
prepare();
scanf("%lld%d",&x,&m);
for(int i=1;i<=n;i++)
{
get(x,i);
if(db&&da*1.0/db<minx)
{
minx=da*1.0/db;
ans=i;
}
}
printf("%d\n",ans);
for(int i=1;i<=m;i++)
{
scanf("%d%lld",&t,&x);
get(x,t);
printf("%d %d",da,db);
if(i!=m)//可能是因为我脸黑,被洛谷判了too many lines才加的
printf("\n");
}
return 0;
}