题意
有一个人在长为 n n 的数轴上从 开始,每次向右走一步, x→x+1 x → x + 1 。同时给出 k k 对关键点 ,如果走到 ai a i 就要跳到 bi b i 。
现在给出他每天走的步数,假如某天他往回走了他的速度会 ×2 × 2 。有 q q 个询问,每次给出初始速度问最少多少天走到 。
n≤109,k,q≤2×105 n ≤ 10 9 , k , q ≤ 2 × 10 5
做法
//希望自己以后多思考思考。。。不要动不动就放弃
来说这题。
首先可以发现路径是唯一的,所以可以处理出所有关键边经过的顺序,可以用set维护。
然后对于每个询问就可以二分找到第一条后退边,模拟即可。由于经过后退边以后速度会翻倍,就能保证最多只会操作log次。。
总时间复杂度 O(nlog2n) O ( n log 2 n ) 。
代码
注意细节。//define和qpow啥的不用理会。。。
#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define per(i,x,y) for (int i=(x); i>=(y); i--)
#define ll long long
#define ld long double
#define inf 1000000000
#define INF 1000000000000000000ll
#define pii pair<int,int>
#define F first
#define S second
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define sqr(x) ((x)*(x))
#define cmin(x,y) (x)=(y)<(x)?(y):(x)
#define cmax(x,y) (x)=(y)>(x)?(y):(x)
#define mset(x,y) memset((x),(y),sizeof(x))
#define mcpy(x,y) memcpy((x),(y),sizeof(y))
using namespace std;
const ld pi=acos(-1);
const ld eps=1e-8;
header files
ll read(){
char ch=getchar(); ll x=0; int op=1;
for (; !isdigit(ch); ch=getchar()) if (ch=='-') op=-1;
for (; isdigit(ch); ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*op;
}
void write(ll a){
if (a<0) putchar('-'),a=-a;
if (a>=10) write(a/10); putchar(a%10+'0');
}
// fast i/o //
#ifdef mod
ll ksm(ll x,ll p){
ll ret=1;
for (; p; p>>=1,x=x*x%mod) if (p&1) ret=ret*x%mod;
return ret;
}
ll get_inv(ll x){
return ksm(x,mod-2);
}
#else
ll ksm(ll x,ll p){
ll ret=1;
for (; p; p>>=1,x=x*x) if (p&1) ret=ret*x;
return ret;
}
#endif
qpow
#define N 200005
int n,m,q,cnt; ll dis[N],b[N],ans;
struct node{
int x,y,z; node(){}
node(int x_,int y_,int z_){ x=x_,y=y_,z=z_; }
bool operator < (const node &t) const{
return x<t.x;
}
}a[N];
//#define local
int main(){
#ifdef local
freopen("test.in","r",stdin); freopen("test.out","w",stdout);
#endif
n=read(),m=read(); set<node> s;
rep (i,1,m){
int x=read(),y=read(),z; if (x>y) z=1; else z=0;
s.insert(node(x,y,z));
}
int now=0;
while (1){
set<node>::iterator it=s.lower_bound(node(now,0,0));
if (it==s.end()) break;
a[++cnt]=*it; now=(*it).y; s.erase(it);
}
/*cerr<<cnt<<endl;
rep (i,1,cnt){
cerr<<a[i].x<<' '<<a[i].y<<endl;
}*/
//会经过cnt条关键边
now=0;
rep (i,1,cnt){
dis[i]=dis[i-1]+abs(a[i].x-now)+1;//dis[i]表示从0走到第i条边终点的距离
b[i]=b[i-1]+a[i].z; now=a[i].y;
}
dis[cnt+1]=dis[cnt]+abs(n-now); b[cnt+1]=inf;
//rep (i,1,cnt+1) cerr<<dis[i]<<' '; cerr<<endl;
//rep (i,1,cnt+1) cerr<<b[i]<<' '; cerr<<endl;
//exit(0);
q=read();
while (q--){
ll x=read(),all=0; now=ans=0;
while (1){
//找第一条后退边
int pos=upper_bound(b+1,b+1+cnt+1,b[now])-b;//b[pos]>b[now]
//cerr<<"pos: "<<pos<<", now: "<<now<<", all="<<all<<endl;
if (pos>cnt){
ans+=(dis[pos]-all-1)/x+1; break;
}
if (dis[pos]-all>x){
int tmp=(dis[pos]-all-1)/x;
ans+=tmp; all+=(ll)tmp*x;
continue;
}
all+=x;
pos=upper_bound(dis+1,dis+1+cnt+1,all)-dis-1;
now=pos; x<<=1; ans++;
if (all>=dis[cnt+1]) break;
}
write(ans),puts("");
}
return 0;
}
// sample data:
/*
7 3
2 5
1 3
4 2
2
1
2
6
3
======
12 4
2 7
8 3
5 10
7 6
100
5
*/
// rest:
/*
*/
/*
If you find any bug in my code or solution, please tell me. Thanks so much.
email: 2411280037@qq.com
*/