JZOJ5865. 【NOIP2018模拟9.11】假期旅行

这里写图片描述
这里写图片描述

题解

a i 表示从i这个位置出发,只用一个座位,最远可以到达的地方。
这个可以用线段树求出来。
考虑倍增,
f i , j 表示从i出发,换 2 j 次座位,最远到达的位置,
这个就跟普通的倍增没有区别,
然后求答案也是倍增。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#define N 200003
#define db double
#define P putchar
#define G getchar
#define ls (x<<1)
#define rs (x<<1|1)
#define M ((l+r)>>1)
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    int w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int max(int x,int y){return x>y?x:y;}
void write(int x){if(x>9) write(x/10);P(x%10+'0');}

struct node
{
    int l,r,a;
}a[N];

int n,m,k,st,fi,q,cnt,op,lst,mr,ans;
int f[23][N],z[23];
int opl,opr,ops,mx[N*4],lazy[N*4];

bool cmp1(node a,node b)
{
    return a.a<b.a || (a.a==b.a && a.l<b.l) || (a.a==b.a && a.l==b.l && a.r<b.r);
}

void down(int x)
{
    if(!lazy[x])return;
    mx[ls]=max(mx[ls],lazy[x]);
    mx[rs]=max(mx[rs],lazy[x]);
    lazy[ls]=max(lazy[x],lazy[ls]);
    lazy[rs]=max(lazy[x],lazy[rs]);
}

int find(int x,int l,int r)
{
    if(l==r)return mx[x];
    down(x);
    int m=M;
    return (opl<=m)?find(ls,l,m):find(rs,m+1,r);
}

void work(int x,int l,int r)
{
    if(opl<=l && r<=opr)
    {
        lazy[x]=max(lazy[x],ops);
        mx[x]=max(mx[x],ops);
        return;
    }
    down(x);
    int m=M;
    if(opl<=m)work(ls,l,m);
    if(m<opr)work(rs,m+1,r);
    mx[x]=max(mx[ls],mx[rs]);
}

int main()
{
    freopen("trip.in","r",stdin);
    freopen("trip.out","w",stdout);

    read(n);read(m);read(k);
    for(int i=1;i<=m;i++)
        read(a[i].l),read(a[i].r),read(a[i].a);
    sort(a+1,a+m+1,cmp1);op=1;

    for(int i=1;i<=k;i++)
    {
        lst=1;
        for(;a[op].a==i;op++)
        {
            if(lst<a[op].l)
            {
                opl=lst,opr=a[op].l-1;ops=a[op].l;
                if(opl<=opr)work(1,1,n);
            }

            mr=a[op].r;
            for(;a[op+1].l<=mr && a[op+1].a==i;op++)mr=max(mr,a[op+1].r);
            lst=mr;
        }

        if(lst<n)opl=lst,opr=ops=n,work(1,1,n);
    }

    for(int i=1;i<n;i++)
    {
        opl=i,f[0][i]=find(1,1,n);
        if(!f[0][i])f[0][i]=n+1;
    }

    z[0]=1;f[0][n]=n;f[0][n+1]=n+1;
    for(int j=1;j<20;j++)
    {
        z[j]=z[j-1]<<1;
        for(int i=1;i<=n+1;i++)
            f[j][i]=f[j-1][f[j-1][i]];
    }

    /*for(int i=1;i<=n;i++)
        printf("%d\n",f[0][i]);*/

    for(read(q);q;q--)
    {
        read(st);read(fi);

        ans=0;
        for(int j=19;j>=0;j--)
            if(f[j][st]<fi)
            {
                st=f[j][st];
                ans=ans+z[j];
            }
        ans++;st=f[0][st];

        if(st>n || st<fi)P('-'),P('1');
            else write(ans);
        P('\n');
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/lijf2001/article/details/82669672