P1081 开车旅行

P1081 开车旅行

排序优化+倍增

其实这道题一开始是一点也没有头绪,知道有高人指点了一下。说并不需要拘束于出发点和路径长度,也就是问题1.2。不过一个是固定路径长度的询问,另一个是给定起点和路径长度的询问。

所以问题一和问题二是可以使用一个函数解决的,而且对于一个城市来说,在不考虑路程的情况下,路线是一定的。

然后我们就可以从遍历图变成枚举终点然后判断路程是否合法。

然后为了加速就可以使用倍增处理

对于每个城市,我们需要找他的最近点和次近点。O(N^2)会超时,这时候我们就需要优化可以考虑双向链表进行优化。

我们先按海拔进行排序,然后将标号为1的点拿出来进行处理,显然,只有在链表中的左右相邻的两个的城市(一个方向)才有可能是满足条件的点

然后再将处理完最近和次近的点在链表中删除(因为路径方向是有序的),这时候标号为2的点就成了标号为1的点,这样就可以了。

每次询问,使用倍增进行摸♂索

#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using std::sort;
using std::abs;
const int maxn=101000;
struct node
{
    int x;
    int y;
    int l,r;
};
node city[maxn];
int pos[maxn];
long long dis[maxn][2];
int to[maxn][2];
int stf[maxn][20];
long long sta[maxn][20];
long long stb[maxn][20];
int n;
bool compare(const node &a,const node &b)
{
    return a.y<b.y;
}
int read()
{
    int res=0,f=1;char c=getchar();
    while(c>'9'||c<'0')
    {
        if(c=='-')	f=-1;
        c=getchar();	
    }
    while(c>='0'&&c<='9')
    {
        res=res*10+c-'0';
        c=getchar();
    }
    return res*f;
}
void make_dis(int i,int j)
{
    int a=0x7fffffff,b=0x7fffffff,c=-1,d=-1;
    for(int l=city[j].l,k=1;l>0&&k<=2;l=city[l].l,k++)
    {
        int pas=abs(city[j].y-city[l].y);
        if(city[l].x<city[j].x)	continue;
        if(a>pas||(a==pas&&city[c].y>city[l].y))
        {
            b=a;d=c;
            a=pas;
            c=l;
        }
        else	if(b>pas||(b==pas&&city[d].y>city[l].y))
        {
            b=pas;
            d=l;
        }
    }
    for(int r=city[j].r,k=1;r<=n&&k<=2;r=city[r].r,k++)
    {
        int pas=abs(city[j].y-city[r].y);
        if(city[r].x<city[r].x)	continue;
        if(a>pas||(a==pas&&city[c].y>city[r].y))
        {
            b=a;d=c;
            a=pas;
            c=r;
        }
        else	if(b>pas||(b==pas&&city[d].y>city[r].y))
        {
            b=pas;
            d=r;
        }
    }//不大会写这种东西
    city[city[j].l].r=city[j].r;
    city[city[j].r].l=city[j].l;
    dis[i][0]=(a == 0x7fffffff ? 0 : a);
    dis[i][1]=(b == 0x7fffffff ? 0 : b);
    to[i][0]= ( c == -1 ? 0 : city[c].x );
    to[i][1]= ( d == -1 ? 0 : city[d].x );
}
void make_st()
{
    for(int i=1;i<=n;i++)
    {
        stf[i][0]=to[to[i][1]][0];
        sta[i][0]=dis[i][1];
        stb[i][0]=dis[to[i][1]][0];
    }
    for(int i=1;i<=19;i++)
        for(int j=1;j<=n;j++)
        {
            stf[j][i]=stf[stf[j][i-1]][i-1];
            sta[j][i]=sta[j][i-1]+sta[stf[j][i-1]][i-1];
            stb[j][i]=stb[j][i-1]+stb[stf[j][i-1]][i-1];
        }
}
void query(int k,int x,long long &a,long long &b)
{
    a=0,b=0;
    for(int i=19;i>=0;i--)
    {
        if(!stf[k][i])	continue;
        if(a+b+sta[k][i]+stb[k][i]>x)	continue;
        a+=sta[k][i];
        b+=stb[k][i];
        k=stf[k][i];
    }
    if(a+b+dis[k][1]<=x)
        a+=dis[k][1];
    return ;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        city[i].x=i;
        city[i].y=read();
    }
    sort(city+1,city+1+n,compare);//按照海拔排序
    for(int i=1;i<=n;i++)
    {
        city[i].l=i-1;
        city[i].r=i+1;
        pos[city[i].x]=i;//链成链表,记录每个城市在链表中的位置
    }
    for(int i=1;i<=n;i++)
        make_dis(i,pos[i]);
    make_st();
    int x=read();
    long long a1=-0x7fffffff,a2=-0x7fffffff;
    long long m1=0,m2=0;
    double minn=0x7fffffff;
    for(int i=1;i<=n;i++)
    {
        long long a,b;
        query(i,x,a,b);
        if(b&&1.0*a/b<minn)
        {
            a2=i;
            minn=1.0*a/b;
            a1=0x7fffffff;
        }
        if(!b&&city[pos[i]].y>a1)
        {
            a1=city[pos[i]].y;
            a2=i;
        }
    }
    printf("%d
",a2);
    int m=read(),s;
    for(int i=1;i<=m;i++)
    {
        long long a,b;
        s=read();x=read();
        query(s,x,a,b);
        printf("%lld %lld
",a,b);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Lance1ot/p/9399245.html