LCT 维护树上信息合并
众所周知,本题的代码可以不到 2k,那些场上迅速过了的大多都预存了模板,我也不是说这样不行,不过即使不预存模板也能首 A,因为有一个能常数之外偏序掉树剖的数据结构:Link-Cut-Tree!
首先本题的信息具有结合律,可以看作一种矩阵,鱼框的状态只有五种,我们将一条链的信息看作从鱼框的每一种状态开始,经过这条链之后会变成什么状态,吃下了几条阴阳鱼,实现时可以将末三位表示状态:
struct dat{
int p[5];//0,10,20,11,21;
dat operator*(const dat &z)const{
return{
((p[0]>>3)<<3)+z.p[p[0]&7],
((p[1]>>3)<<3)+z.p[p[1]&7],
((p[2]>>3)<<3)+z.p[p[2]&7],
((p[3]>>3)<<3)+z.p[p[3]&7],
((p[4]>>3)<<3)+z.p[p[4]&7]
};
}
void init(int d){
if(d)*this={3,8,9,4,4};
else *this={1,2,2,8,11};
}
void init(){*this={0,1,2,3,4};}
void put(){
for(int i=0;i<5;++i)
printf("%d%c",p[i]," \n"[i==4]);
}
}
而每次询问的初始状态都是
为了实现方便需要换根,可以将正的和反的信息都存下来,翻转时交换即可。
于是代码很好写:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct dat{
int p[5];//0,10,20,11,21;
dat operator*(const dat &z)const{
return{
((p[0]>>3)<<3)+z.p[p[0]&7],
((p[1]>>3)<<3)+z.p[p[1]&7],
((p[2]>>3)<<3)+z.p[p[2]&7],
((p[3]>>3)<<3)+z.p[p[3]&7],
((p[4]>>3)<<3)+z.p[p[4]&7]
};
}
void init(int d){
if(d)*this={3,8,9,4,4};
else *this={1,2,2,8,11};
}
void init(){*this={0,1,2,3,4};}
void put(){
for(int i=0;i<5;++i)
printf("%d%c",p[i]," \n"[i==4]);
}
}s1[N],s2[N],v[N];
int n,q,cl[N],rv[N],t[N][2],f[N];
#define ls t[x][0]
#define rs t[x][1]
#define tp(x) (t[f[x]][1]==x)
#define in(x) (t[f[x]][0]==x||tp(x))
void pp(int x){
s1[x]=s2[x]=v[x];
if(ls)s1[x]=s1[ls]*s1[x],s2[x]=s2[x]*s2[ls];
if(rs)s1[x]=s1[x]*s1[rs],s2[x]=s2[rs]*s2[x];
}
void rev(int x){
rv[x]^=1,swap(ls,rs);
swap(s1[x],s2[x]);
}
void pd(int x){
if(rv[x]){
if(ls)rev(ls);
if(rs)rev(rs);rv[x]=0;
}
}
void ppd(int x){
if(in(x))ppd(f[x]);pd(x);
}
void rot(int x){
int y=f[x],k=tp(x),w=t[x][!k];
t[f[w]=t[x][!k]=y][k]=w;
if(in(y))t[f[y]][tp(y)]=x;
f[x]=f[y],f[y]=x,pp(y);
}
void splay(int x){
ppd(x);
for(int y=f[x];in(x);rot(x),y=f[x])
if(in(y))rot(tp(x)^tp(y)?x:y);pp(x);
}
void acs(int x){
for(int y=0;x;x=f[y=x])
splay(x),rs=y,pp(x);
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>q;
int i,j,k,l,r,x,y;
for(x=1;x<=n;++x)cin>>cl[x],v[x].init(cl[x]),pp(x);
for(i=1;i<n;++i){
cin>>x>>y;
acs(x),splay(x),rev(x),f[x]=y;
}
s1[0].init(),s1[0].init();
while(q--){
cin>>k>>x;
if(k==1)splay(x),v[x].init(cl[x]^=1),pp(x);
else{
cin>>y,acs(x),splay(x),rev(x);
acs(y),splay(x);
printf("%d\n",s1[x].p[0]>>3);
}
}return 0;
}