倍增从入门到入土

入门

P1081 [NOIP2012 提高组] 开车旅行

tj前:看到第一第二大,可以倍增维护,但是这建边也太恶心了,然后对于第一问我在挨个点跑一边?倍增起码有个区间吧,宁给我个 \(x_0\) 我也不知道该从那么跑哇,只能从头往后排,这不曼斯?
比值可以模拟,但是这该怎么跑

tj后:看了看可以模拟,我先试试
70分暴力模拟

/*
    c1[i] 距离i最近的城市
    c2[i] 距离i次进的城市 
    dis1[i] 从i到c[i]的距离
    dis2[i] 同理 次二进的 
    A---2
    B---1+ 
*/
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <bits/stdc++.h>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e7+10;
const int B = 1e6+10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
  for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n,m,h[B],xl,p;

int dis1[B],dis2[B],c1[B],c2[B];

double minv=INT_MAX;

main()
{
    int x,y;
    n=read();
    for (int i=1;i<=n;i++) h[i]=read();
    
    for (int i=n-1;i>=1;i--)
    {
        int minx=i+1,minxx=0;
        dis1[i]=abs(h[i]-h[i+1]);
        for (int j=i+2;j<=n;j++)
        {
            if (dis1[i]>abs(h[i]-h[j]) || (dis1[i]==abs(h[i]-h[j]) && h[j]<h[minx]))
            {
                minxx=minx;
                minx=j;
                dis2[i]=dis1[i];
                dis1[i]=abs(h[i]-h[j]); 
            }
            else if (dis2[i]==0 || dis2[i]>abs(h[i]-h[j]) || (dis2[i]==abs(h[i]-h[j]) && h[j]<h[minxx]))
            {
                minxx=j;
                dis2[i]=abs(h[i]-h[j]);
            }
        }
        c1[i]=minx;
        c2[i]=minxx;
    }
    
    xl=read();
    int ans=0;
    for (int i=1;i<=n;i++)
    {
        int js=0,sum=0,a=0,b=0;
        int s=i;
        while (1)
        {
            
            if(!js)
            {
                if (a+b+dis2[s]>xl || !c2[s]) break;
                a+=dis2[s];
                s=c2[s];
            }
            else
            {
                if (a+b+dis1[s]>xl || !c1[s]) break;
                b+=dis1[s];
                s=c1[s];
            }
            js^=1;
        } 
        if (!ans || 1.0*a / b - minv < -0.00000001 || (fabs(1.0*a / b - minv) <= 0.00000001&&h[ans] < h[i]))
        {
            minv = 1.0*a / b;
            ans = i;
        }
    }
    
    printf("%lld\n",ans);
    p=read();
    while (p--)
    {
        int w,js=0,a=0,b=0;
        x=read(),y=read();
        int s=x;
        while (1)
        {
            if(!js)
              {
                if (a+b+dis2[s]>y || !c2[s]) break;
                a+=dis2[s];
                s=c2[s];
            }
            else
            {
                if (a+b+dis1[s]>y || !c1[s]) break;
                b+=dis1[s];
                s=c1[s];
            }
            js^=1;
        }
        printf("%lld %lld\n",a,b);
    } 
    return 0;
} 

倍增优化,双向链表初始化
做完我都在想今天晚上我为甚选择的宁,一晚上没了

/*
    c1[i] 距离i最近的城市
    c2[i] 距离i次进的城市 
    dis1[i] 从i到c[i]的距离
    dis2[i] 同理 次二进的 
    A---2
    B---1+ 
*/
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <bits/stdc++.h>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e7+10;
const int B = 1e6+10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
  for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int n,m,h[B],xl,p;

int pos[B],dis1[B],dis2[B],c1[B],c2[B];
int  c3[B][21],dist3[B][21], dist4[B][21], dist5[B][21];

double minv=INT_MAX;

struct node{int h,bh,last,next;}q[B];

bool cmp(node a,node b){return a.h<b.h;}

void updata(int i,int loc,int x)
{
    if (x>=1 && x<=n)
        {
            if (!dis1[i] || dis1[i]>abs(q[loc].h -q[x].h) || (dis1[i]==abs(q[loc].h -q[x].h) && q[x].h <q[pos[c1[i]]].h))
            {
                c2[i]=c1[i];
                c1[i]=q[x].bh;
                dis2[i]=dis1[i];
                dis1[i]=abs(q[loc].h -q[x].h); 
            }
            else if (dis2[i]==0 || dis2[i]>abs(q[loc].h -q[x].h) || (dis2[i]==abs(q[loc].h -q[x].h) && q[x].h <q[pos[c2[i]]].h))
            {
                c2[i]=q[x].bh;
                dis2[i]=abs(q[loc].h -q[x].h);
            }
        }
}

main()
{
    int x,y;
    n=read();
    for (int i=1;i<=n;i++) q[i].h=read(),q[i].bh=i;
    sort(q+1,q+1+n,cmp);
    
    for (int i=1;i<=n;i++)
    {
        pos[q[i].bh]=i;
        if (i!=1) q[i].last=i-1;
        if (i!=n) q[i].next=i+1;
    }
    
    for (int i=1;i<=n;i++)
    {
        int loc = pos[i];
        updata(i, loc, q[q[loc].last].last);
        updata(i, loc, q[loc].last);
        updata(i, loc, q[loc].next);
        updata(i, loc, q[q[loc].next].next);
        if (q[loc].last)q[q[loc].last].next = q[loc].next;
        if (q[loc].next)q[q[loc].next].last = q[loc].last;
        q[loc].last = q[loc].next = 0;
    }
    
     for ( int i = 1; i <= n; ++i)
    {
        dist4[i][0] = dis2[i];
        dist5[i][0] = dis1[c2[i]];
        dist3[i][0] = dis2[i] + dis1[c2[i]];
        c3[i][0] = c1[c2[i]];
    }
    
    for ( int j = 1; j <= 20; ++j)
        for ( int i = 1; i <= n; ++i)
        {
            c3[i][j] = c3[c3[i][j - 1]][j - 1];
            if (c3[i][j])
            {
                dist3[i][j] = dist3[i][j - 1] + dist3[c3[i][j - 1]][j - 1];
                dist4[i][j] = dist4[i][j - 1] + dist4[c3[i][j - 1]][j - 1];
                dist5[i][j] = dist5[i][j - 1] + dist5[c3[i][j - 1]][j - 1];
            }
        }
    int xx = read(), ans = 0;
    for (int i = 1; i <= n; ++i)
    {
         int a = 0, b = 0, loc = i, x0 = xx;
        for ( int j = 20; j >= 0; --j)
        {
            if (dist3[loc][j] && x0 >= dist3[loc][j])
            {
                x0 -= dist3[loc][j];
                a += dist4[loc][j];
                b += dist5[loc][j];
                loc = c3[loc][j];
            }
        }
        if (dis2[loc] <= x0)a += dis2[loc];
        if (a <= 0)continue;
        if (!ans || 1.0*a / b - minv < -0.00000001 || (fabs(1.0*a / b - minv) <= 0.00000001&&q[pos[ans]].h < q[pos[i]].h))
        {
            minv = 1.0*a / b;
            ans = i;
        }
    }
    
    printf("%lld\n",ans);
    p=read();
    while (p--)
    {
         int s = read(), x = read(), a = 0, b = 0;
        for ( int j = 20; j >= 0; --j)
        {
            if (dist3[s][j] && x >= dist3[s][j])
            {
                x -= dist3[s][j];
                a += dist4[s][j];
                b += dist5[s][j];
                s = c3[s][j];
            }
        }
        if (dis2[s] <= x)a += dis2[s];
        printf("%lld %lld\n", a, b);
    } 
    return 0;
} 

posted @ 2021-03-12 19:19  zxsoul  阅读(54)  评论(5编辑  收藏  举报