P3203 [HNOI2010]弹飞绵羊
题目描述
solution
这是一道LCT的裸题。
但是我并不想用LCT解决此题(In fact 是不会LCT ~QAQ)
于是我们开始大力分块。
考虑把弹跳装置分块,我们每次需要知道在一个块内需要跳几次以及跳出这个块后到达哪一个节点,这样保证了每一个块的信息不会对其他块的信息产生影响,且我们可以用DP在 的时间内预处理出上述信息。
查询时每次跳转到一个之后的块中,沿途统计答案。
修改时由于块与块之间独立,因此直接暴力修改需要修改的一块信息即可。
时间复杂度
Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+50;
int a[MAXN],color[MAXN],n,Size;
struct fnode{int x,y; } f[MAXN];
inline int read()
{
int f=1,x=0; char c=getchar();
while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
return x*f;
}
void change(int i) //求出i位置的信息
{
if (i+a[i]<=n)
{
if (color[i]==color[i+a[i]]) f[i]=(fnode){f[i+a[i]].x,f[i+a[i]].y+1};
else f[i]=(fnode){i+a[i],1};
}
else f[i]=(fnode){-1,1};
}
int main()
{
n=read(),Size=trunc(sqrt(n));
for (int i=1;i<=n;i++) a[i]=read(),color[i]=(i-1)/Size+1;
for (int i=n;i>=1;i--) change(i); //预处理
//for (int i=1;i<=n;i++) cout<<i<<":"<<f[i].x<<" "<<f[i].y<<endl;
int Case=read();
while (Case--)
{
int opt=read(),x=read()+1; //标号从0开始
if (opt==1)
{
int ans=0;
while (x!=-1) ans+=f[x].y,x=f[x].x; //统计答案
printf("%d\n",ans);
}
else
{
int y=read(); a[x]=y;
for (int i=color[x]*Size;i>=(color[x]-1)*Size+1;i--) change(i); //用与预处理相同的方法暴力修改
//for (int i=1;i<=n;i++) cout<<i<<":"<<f[i].x<<" "<<f[i].y<<endl;
}
}
return 0;
}