把树转成左儿子右兄弟的那种二叉树的形式
发现一个点能且仅能给他的子树传递order,询问3就变成了询问一个点到根有多少个点
对于传递message,可以给每个点定一个编号0的虚儿子,给他赋权1,就变成了询问两点间路径的权值和,注意要特判一个点是另一个点的祖先的情况,bzoj上的数据有误,不判这个才能过,hdu上的数据是对的可以去那里交
对于操作1,把某个人的一段儿子截下来,可以用n棵splay处理每个人的孩子链表
然后就都是splay,LCT的常规操作了
code:(bz上的AC代码,注释掉了判祖先的那部分)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline void read(int &x)
{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 300010;
int n,m;
int t[maxn],tp;
struct Splay
{
int son[maxn][2],fa[maxn],root[maxn],s[maxn],siz[maxn];
void pushup(const int x){siz[x]=s[x]+siz[son[x][0]]+siz[son[x][1]];}
int build(const int y,const int l,const int r)
{
int mid=l+r>>1,x=t[mid]; fa[x]=y;
if(l==r) return x;
if(l!=mid) son[x][0]=build(x,l,mid-1);
if(mid!=r) son[x][1]=build(x,mid+1,r);
pushup(x);
return x;
}
void rotate(int x,int &k)
{
int y=fa[x],z=fa[y];
if(y==k) k=x;
else if(z) son[z][son[z][1]==y]=x;
fa[x]=z;
int l=son[y][1]==x;
fa[son[y][l]=son[x][!l]]=y;
fa[son[x][!l]=y]=x;
pushup(y);
}
void splay(int x,int &k)
{
for(;x!=k;rotate(x,k))
{
int y=fa[x],z=fa[y];
if(y!=k)
{
if((son[y][1]==x)^(son[z][1]==y)) rotate(x,k);
else rotate(y,k);
}
}pushup(x);
}
int find_(const int r,int k)
{
int x=root[r];
while(1)
{
if(k<=siz[son[x][0]])
{
if(!son[x][0]) return x;
x=son[x][0];
}
else if(k==siz[son[x][0]]+s[x]) return x;
else
{
if(!son[x][1]) return x;
k-=siz[son[x][0]]+s[x];
x=son[x][1];
}
}
}
}S;
struct LinkCutTree
{
int s1[maxn],s2[maxn],c1[maxn],c2[maxn];
int son[maxn][2],fa[maxn];
void pushup(const int x)
{
c1[x]=s1[x]+c1[son[x][0]]+c1[son[x][1]];
c2[x]=s2[x]+c2[son[x][0]]+c2[son[x][1]];
}
bool isroot(const int x) { return (son[fa[x]][0]!=x&&son[fa[x]][1]!=x); }
void rotate(const int x)
{
int y=fa[x],z=fa[y];
if(!isroot(y)) son[z][son[z][1]==y]=x;
fa[x]=z;
int l=son[y][1]==x;
fa[son[y][l]=son[x][!l]]=y;
fa[son[x][!l]=y]=x;
pushup(y);
}
void splay(const int x)
{
for(;!isroot(x);rotate(x))
{
int y=fa[x],z=fa[y];
if(!isroot(y))
{
if((son[y][1]==x)^(son[z][1]==y)) rotate(x);
else rotate(y);
}
}pushup(x);
}
void access(int x)
{
int y=0;
for(;x;y=x,x=fa[x])
{
splay(x); son[x][1]=y; pushup(x);
}
}
void Link(int a,int b)
{
access(b); splay(b); fa[b]=a;
}
void Cut(int a)
{
access(a); splay(a);
son[a][0]=fa[son[a][0]]=0; pushup(a);
}
int LCA(int a,int b)
{
access(b);
int y=0;
for(int x=a;x;y=x,x=fa[x])
{
splay(x); son[x][1]=y; pushup(x);
if(fa[x]==0) return x;
}
}
int go(int x,int to)
{
while(son[x][to]) x=son[x][to];
return x;
}
int las(int a,int b)
{
access(b); splay(a);
return go(son[a][1],0);
}
int sum1(int x)
{
access(x); splay(x);
return c1[son[x][0]]+s1[x];
}
int sum2(int x)
{
access(x); splay(x);
return c2[son[x][0]];
}
}LCT;
void Move(const int r1,int p,int c,const int r2,int q)
{
c=p+c-1;
int ll=S.find_(r1,p-1),l=S.find_(r1,p);
int r=S.find_(r1,c),rr=S.find_(r1,c+1);
int tol=S.find_(r2,q),tor=S.find_(r2,q+1);
LCT.Cut(l); if(rr<=n) LCT.Cut(rr),LCT.Link(ll,rr);
if(tor<=n) LCT.Cut(tor),LCT.Link(r,tor);
LCT.Link(tol,l);
S.splay(ll,S.root[r1]); S.splay(rr,S.son[ll][1]);
int y=S.son[rr][0]; S.son[rr][0]=0; S.splay(rr,S.root[r1]);
S.splay(tol,S.root[r2]); S.splay(tor,S.son[tol][1]);
S.son[tor][0]=y; S.fa[y]=tor; S.splay(y,S.root[r2]);
}
int solve1(const int x,const int y)
{
int ff=LCT.LCA(x,y);
if(ff==x)
{
int a1=LCT.sum1(y),a2=LCT.sum1(x);
int ans=a1-a2+1;
//if(LCT.las(x,y)>n) ans--;
return ans;
}
else if(ff==y)
{
int a1=LCT.sum1(x),a2=LCT.sum1(y);
int ans=a1-a2+1;
//if(LCT.las(y,x)>n) ans--;
return ans;
}
else
{
int a1=LCT.sum1(x);
int a2=LCT.sum1(y);
int a3=2*LCT.sum1(ff);
return a1+a2-a3+1;
}
}
int solve2(const int x) { return LCT.sum2(x); }
int main()
{
read(n); read(m);
for(int i=1;i<=n;i++) S.s[i]=S.siz[i]=1;
for(int i=1;i<=n;i++)
{
LCT.s2[i]=LCT.c2[i]=1;
LCT.s1[n+i]=LCT.c1[n+i]=1;
LCT.Link(i,n+i);
int cc,la; read(cc);
la=t[tp=1]=n+i;
while(cc--)
{
int x; read(x); t[++tp]=x;
LCT.Link(la,x); la=x;
}
t[++tp]=n+n+i;
S.root[i]=S.build(0,1,tp);
}
while(m--)
{
int ki; read(ki);
if(ki==1)
{
int x,p,c,y,q;
read(x),read(p),read(c);
read(y),read(q);
Move(x,p,c,y,q);
}
else if(ki==2)
{
int x,y; read(x); read(y);
printf("%d\n",solve1(x,y)-1);
}
else
{
int x; read(x);
printf("%d\n",solve2(x));
}
}
return 0;
}