版权声明:谁他喵没事儿会转我的博客啊QAQ,有没有人看都是一回事儿。。。 https://blog.csdn.net/f2935552941/article/details/82215783
题目大意:
这题基本上就是弹飞绵羊的树上版,所以题意就不多讲了。
可以参考另外一篇博客:弹飞绵羊普通版
解题思路:
首先肯定可以用树分块来写,思路就是跟线性的是一样的。其次的话如果用LCT的话近似裸题,只是需要求一下对于点x,向上跳k次会跳到哪个点,用倍增求出来即可。然后我添加了一个n+1作为1结点的父亲,跳出去的点默认跳到n+1,之后就和线性的一样了,这次主要也是为了测试LCT的板子,发现我的板子其实不够优秀啊,裸跑998ms,所以用了dls的快读,500+ms过了。。。
Ac代码:
#include<bits/stdc++.h>
#define T_T system("pause")
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=1e9+7;
vector<int> v[maxn];
int n,m,dp[maxn][20],dep[maxn],a[maxn];
namespace IO{ //快读板子
#define BUF_SIZE 100000
#define OUT_SIZE 100000
#define ll long long
//fread->read
bool IOerror=0;
inline char nc(){
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if (p1==pend){
p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
if (pend==p1){IOerror=1;return -1;}
//{printf("IO error!\n");system("pause");for (;;);exit(0);}
}
return *p1++;
}
inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
inline void read(int &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
inline void read(ll &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
inline void read(double &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (ch=='.'){
double tmp=1; ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');
}
if (sign)x=-x;
}
inline void read(char *s){
char ch=nc();
for (;blank(ch);ch=nc());
if (IOerror)return;
for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch;
*s=0;
}
inline void read(char &c){
for (c=nc();blank(c);c=nc());
if (IOerror){c=-1;return;}
}
//fwrite->write
struct Ostream_fwrite{
char *buf,*p1,*pend;
Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;}
void out(char ch){
if (p1==pend){
fwrite(buf,1,BUF_SIZE,stdout);p1=buf;
}
*p1++=ch;
}
void print(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void println(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1); out('\n');
}
void print(ll x){
static char s[25],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void println(ll x){
static char s[25],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1); out('\n');
}
void print(double x,int y){
static ll mul[]={1,10,100,1000,10000,100000,1000000,10000000,100000000,
1000000000,10000000000LL,100000000000LL,1000000000000LL,10000000000000LL,
100000000000000LL,1000000000000000LL,10000000000000000LL,100000000000000000LL};
if (x<-1e-12)out('-'),x=-x;x*=mul[y];
ll x1=(ll)floor(x); if (x-floor(x)>=0.5)++x1;
ll x2=x1/mul[y],x3=x1-x2*mul[y]; print(x2);
if (y>0){out('.'); for (size_t i=1;i<y&&x3*mul[i]<mul[y];out('0'),++i); print(x3);}
}
void println(double x,int y){print(x,y);out('\n');}
void print(char *s){while (*s)out(*s++);}
void println(char *s){while (*s)out(*s++);out('\n');}
void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
~Ostream_fwrite(){flush();}
}Ostream;
inline void print(int x){Ostream.print(x);}
inline void println(int x){Ostream.println(x);}
inline void print(char x){Ostream.out(x);}
inline void println(char x){Ostream.out(x);Ostream.out('\n');}
inline void print(ll x){Ostream.print(x);}
inline void println(ll x){Ostream.println(x);}
inline void print(double x,int y){Ostream.print(x,y);}
inline void println(double x,int y){Ostream.println(x,y);}
inline void print(char *s){Ostream.print(s);}
inline void println(char *s){Ostream.println(s);}
inline void println(){Ostream.out('\n');}
inline void flush(){Ostream.flush();}
#undef ll
#undef OUT_SIZE
#undef BUF_SIZE
};
struct LCT //LCT模板
{
int father[maxn+5],son[maxn+5][2],si[maxn+5];
bool flip[maxn+5];
void init()
{
memset(father,0,sizeof father);
memset(son,0,sizeof son);
memset(si,0,sizeof si);
memset(flip,0,sizeof flip);
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);
}
}tr;
void dfs(int u,int fa) //倍增
{
dp[u][0]=fa;
for(int i=1;i<=19;i++) dp[u][i]=dp[dp[u][i-1]][i-1];
for(int i=0;i<v[u].size();i++)
dfs(v[u][i],u);
}
int query(int x,int t) //查询x结点向上跳t次的结点
{
for(int i=17;i>=0;i--)
{
if((1<<i)<=t)
{
if(dp[x][i]) x=dp[x][i],t-=(1<<i);
else
{
x=n+1;
break;
}
}
}
return x;
}
int main()
{
int QAQ;
IO::read(QAQ);
while(QAQ--)
{
IO::read(n); tr.init();
for(int i=0;i<=n+1;i++) v[i].clear();
for(int i=2;i<=n;i++)
{
int x; IO::read(x);
v[x].push_back(i);
}
v[n+1].push_back(1);
dfs(n+1,0);
for(int i=1;i<=n;i++) //正常的连边
{
IO::read(a[i]); a[i]=query(i,a[i]);
tr.Link(a[i],i);
}
IO::read(m);
while(m--)
{
int flag,x,y;
IO::read(flag);
if(flag==1) //查询x到n+1结点的链上点的个数
{
IO::read(x);
tr.make_ro(n+1);tr.Access(x);tr.Splay(x);
IO::println(tr.si[x]-1);
}
if(flag==2)
{
IO::read(x),IO::read(y);
tr.Cut(x,a[x]),tr.Link(x,query(x,y));
a[x]=query(x,y);
}
}
}
}