之前用分塊解過這道題,不過最近學到了LCT,發現它也是LCT的模闆題,就用LCT做了一下。
分塊解法:https://blog.csdn.net/f2935552941/article/details/78157052
LCT的話,推薦一篇部落格,講的比較清楚,但是如果想深入了解的話建議可以找國家集訓隊的論文看一下。
推薦部落格:https://blog.csdn.net/JeremyGJY/article/details/51078087
解題思路:
這道題目具體就是我們對于 x 和 x+a[x] 建立一條邊,如果 x+a[x] 大于 n,就預設建到 n+1 即可,之後查詢 x 跳出次數,就是把 x 到 n+1 的鍊挑出來,這條鍊上的結點數-1 即可。
修改的話就用正常的删邊和建邊實作即可,
發現了大佬的一個闆子,感覺還挺不錯的。
Ac代碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const int mod=1e9+7;
const int INF=1e9+7;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
int n,m,a[maxn];
struct LCT //LCT模闆
{
int father[maxn+5],son[maxn+5][2],si[maxn+5];
bool flip[maxn+5];
void init(){ for(int i=1;i<=n+1;i++) si[i]=1; }
void Pushup(int p) {si[p]=si[son[p][0]]+1+si[son[p][1]];}
void Add_flip(int p) {swap(son[p][0],son[p][1]);flip[p]^=1;}
void Pushdown(int p)
{
if (!flip[p]) return;
if (son[p][0]) Add_flip(son[p][0]);
if (son[p][1]) Add_flip(son[p][1]);
flip[p]=false;
}
bool is_ro(int p) {return p!=son[father[p]][0]&&p!=son[father[p]][1];}
void Rotate(int p)
{
int fa=father[p],d=p==son[fa][0];
if (!is_ro(fa)) son[father[fa]][fa==son[father[fa]][1]]=p;
son[fa][d^1]=son[p][d];father[son[p][d]]=fa;son[p][d]=fa;
Pushup(fa);Pushup(p);father[p]=father[fa];father[fa]=p;
}
int top,stk[maxn+5];
void Splay(int p)
{
stk[++top]=p;
for (int i=p;!is_ro(i);i=father[i]) stk[++top]=father[i];
while (top) Pushdown(stk[top--]);
while (!is_ro(p))
{
int fa=father[p];
if (!is_ro(fa))
{
int d1=fa==son[father[fa]][1],d2=p==son[fa][1];
if (d1==d2) Rotate(fa); else Rotate(p);
}
Rotate(p);
}
}
void Access(int p)
{
int lst=0;
while (p)
{
Splay(p);son[p][1]=lst;Pushup(p);
lst=p;p=father[p];
}
}
void make_ro(int p) {Access(p);Splay(p);Add_flip(p);}
void Link(int x,int y) {Access(y);make_ro(y);father[y]=x;}
void Cut(int x,int y)
{
make_ro(y);Access(x);Splay(x);
father[y]=son[x][0]=0;Pushup(x);
}
};
LCT tr;
int main()
{
scanf("%d",&n); tr.init(); //初始化
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),tr.Link(min(i+a[i],n+1),i); //建邊
scanf("%d",&m);
while(m--)
{
int flag,x,y;
scanf("%d",&flag);
if(flag==1)
{
scanf("%d",&x); x++;
tr.make_ro(n+1);tr.Access(x);tr.Splay(x);
printf("%d\n",tr.si[x]-1);
}
else
{
scanf("%d%d",&x,&y); x++;
tr.Cut(min(x+a[x],n+1),x),tr.Link(min(x+y,n+1),x);
a[x]=y;
}
}
//system("pause");
return 0;
}