洛谷 P1081 开车旅行【双向链表+倍增】

倍增数组的20和N写反了反复WAWAWA……
注意到a和b在每个点上出发都会到一个指定的点,所以这样构成了两棵以n点为根的树
假设我们建出了这两棵树,对于第一问就可以枚举起点然后倍增的找出ab路径长度的比值,第二问同理,这里倍增的时候注意是先跳a再跳b,所以同一个点b的倍增数组要从a在这个点的的父亲开始,然后位置倍增数组也是这样,这样位置倍增相当于跳完a再跳b
然后这个树怎么建呢,开一个双向链表,表内按h排升序,因为一个点的最大次大值一定在比它小的值中最大的两个和比它大的值中最小的两个之中,所以直接用链表查即可,然后查完一个点就把它删掉,因为这个点不能用来更新id比他大的点

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m,rl[N],ff[N],gg[N];
long long h[N],f[20][N],g[20][N],fa[20][N],da,db;
struct qwe
{
    int id,l,r;
    long long h;
}a[N];
bool cmp(const qwe &a,const qwe &b)
{
    return a.h<b.h;
}
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void wk(int w,long long x)
{
    da=0,db=0;
    for(int i=17;i>=0;i--)
        if(fa[i][w]!=0&&da+db+f[i][w]+g[i][w]<=x)
            da+=f[i][w],db+=g[i][w],w=fa[i][w];
    if(ff[w]!=0&&da+db+f[0][w]<=x)
        da+=f[0][w];
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        h[i]=a[i].h=read(),a[i].id=i;
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++)
        rl[a[i].id]=i,a[i].l=i-1,a[i].r=i+1;
    a[0].h=1e10,a[n+1].h=1e10;
    for(int i=1;i<=n;i++)
    {
        int ll=a[a[rl[i]].l].l,l=a[rl[i]].l,r=a[rl[i]].r,rr=a[a[rl[i]].r].r;
        if(!l)
            gg[i]=a[r].id,ff[i]=a[rr].id;
        else if(r==n+1)
            gg[i]=a[l].id,ff[i]=a[ll].id;
        else if(abs(h[i]-a[l].h)<=abs(h[i]-a[r].h))
            gg[i]=a[l].id,ff[i]=(abs(h[i]-a[ll].h)<=abs(h[i]-a[r].h))?a[ll].id:a[r].id;
        else
            gg[i]=a[r].id,ff[i]=(abs(h[i]-a[l].h)<=abs(h[i]-a[rr].h))?a[l].id:a[rr].id;
        a[a[rl[i]].l].r=a[rl[i]].r,a[a[rl[i]].r].l=a[rl[i]].l;
        // cerr<<"   "<<ff[i]<<" "<<gg[i]<<endl;
    }
    for(int i=1;i<=n;i++)
    {
        fa[0][i]=gg[ff[i]];
        f[0][i]=abs(h[ff[i]]-h[i]);
        g[0][i]=abs(h[fa[0][i]]-h[ff[i]]);
    }
    for(int i=1;i<=17;i++)
        for(int j=1;j<=n;j++)
            fa[i][j]=fa[i-1][fa[i-1][j]],f[i][j]=f[i-1][j]+f[i-1][fa[i-1][j]],g[i][j]=g[i-1][j]+g[i-1][fa[i-1][j]];
    long long x0=read(),w=0;
    double ans=1e18;
    for(int c=1;c<=n;c++)
    {
        wk(c,x0);
        if(db!=0&&1.0*da/db<ans)
        {
            ans=1.0*da/db;
            w=c;
        }
    }
    printf("%d\n",w);
    m=read();
    while(m--)
    {
        long long s=read(),x=read();
        wk(s,x);
        printf("%lld %lld\n",da,db);
    }
    return 0;
}
posted @ 2018-09-08 10:56  lokiii  阅读(125)  评论(0编辑  收藏  举报