JZOJ5865. 【NOIP2018模拟9.11】假期旅行
程序员文章站
2022-03-31 08:07:50
...
题解
设表示从i这个位置出发,只用一个座位,最远可以到达的地方。
这个可以用线段树求出来。
考虑倍增,
设表示从i出发,换次座位,最远到达的位置,
这个就跟普通的倍增没有区别,
然后求答案也是倍增。
#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;
}
下一篇: NOIP2018 提高组模拟 9.6