CF13E Holes

Description:

\(N\) 个洞,每个洞有相应的弹力,能把这个球弹到 \(i+power[i]\) 位置。当球的位置 \(>N\) 时即视为被弹出。

有两种操作:

  1. 修改某个点的弹力值。
  1. 询一个球从某点几次能够弹出,弹出前的最后一个位置是哪里。

Solution

考虑分块,对于每个点,记录其弹几次能够弹出其所在块,记作\(cnt_i\),弹出其所在块前的最后一个位置,记作\(ls_i\),弹出其所在块后的位置,记作 \(to_i\)

记块长为 \(s\)
由于修改操作只会影响一个块内的答案,所以可以在 \(\Theta(s)\) 的时间里完成修改,又一个球最多跳块数次就可以跳出,所以可以在 \(\Theta(\frac n s)\) 的时间完成查询,取 \(s=\sqrt n\) 可取得最优解,总复杂度 \(\Theta(n\sqrt n)\)

双倍经验


Code

/*If you are full of hope,you will be invincible*/
#include <ctime>
#include <cstdio>
#include <random>
#include <cstring>
#include <iostream>
#include <algorithm>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#include<ext/pb_ds/priority_queue.hpp>
#define ri register int
typedef long long ll;
std::mt19937 hpy(time(nullptr)+(unsigned long long)(new char));
namespace IO{
	constexpr int HL=1<<20;
	char buf[HL],*t1=buf,*t2=buf;
	#ifndef ONLINE_JUDGE
	#define getc() getchar()
	#else
	#define getc() t1==t2&&(t2=(t1=buf)+fread(buf,1,HL,stdin),t1==t2)?EOF:*t1++
	#endif
	inline int read(){static int an,f;an = 0,f = 1;static char ch;ch=getc();
	while(!isdigit(ch))ch=='-'?f=-1:1,ch=getc();
	while(isdigit(ch))an=(an<<3)+(an<<1)+(ch^48),ch=getc();
	return an*f;}
	char buff[HL],*T=buff;
	void flush(){fwrite(buff,1,T-buff,stdout);T=buff;}
	inline void putc(char ch){if(T==buff+HL)flush();*T++=ch;}
	template<typename Tp>
	inline void print(Tp x){if(x<0)putc('-'),x=-x;if(!x)return putc('0'),void();
	static int st[20],tp;while(x)st[++tp]=x%10,x/=10;while(tp)putc(st[tp]^48),--tp;}
}
using IO::read;
using IO::print;
using IO::putc;
constexpr int inf = 0x3f3f3f3f,N = 1e5 + 10,M = sqrt(N) + 10;
int a[N],to[N],bl[N],L[M],R[M],cnt[N],la[N],n,m,siz,tot;
inline int pos(int x){return (x-1)/siz+1;}
inline void Init() {
    n=read(),m=read(),siz=sqrt(n),tot=pos(n);
    for(ri i=1;i<=n;++i) a[i]=read(),bl[i]=pos(i);
    for(ri i=1;i<=tot;++i) L[i] = R[i-1]+1,R[i]=i*siz;
    R[tot] = n;
    for(ri i=n;i>=1;--i) {
        if(i+a[i] > R[bl[i]]) 
            cnt[i] = 1,to[i] = i + a[i],la[i]=i;
        else 
            cnt[i] = cnt[i+a[i]]+1,to[i] = to[i+a[i]],la[i]=la[i+a[i]];
    }
} 
inline void Modify(int x,int k) {
    a[x] = k;
    int pn = pos(x);
    for(ri i=R[pn];i>=L[pn];--i) {
        if(i+a[i] > R[pn]) cnt[i] = 1,to[i] = i + a[i],la[i] = i;
        else cnt[i] = cnt[i+a[i]] + 1,to[i] = to[i+a[i]],la[i]=la[i+a[i]];
    }
}
inline std::pair<int,int> query(int p) {
    int res = 0,lst;
    while(p <= n) {
        res += cnt[p],lst = la[p],p = to[p];
    }
    return std::make_pair(lst,res);
}
int main() {
    Init();
    for(ri i=1;i<=m;++i) {
        int opt=read(),x,y;
        if(opt) {
            x=read();
            std::pair<int,int> p = query(x);
            print(p.first),putc(' '),print(p.second),putc('\n');
        } else  {
            x=read(),y=read();
            Modify(x,y);
        }
    }
    return IO::flush(),0;
}
posted @ 2021-07-21 11:18  feicheng  阅读(44)  评论(0编辑  收藏  举报