题目大意:
给一棵二叉树,每个点有权值,定义每个点的size为其子树的权值和,每个点的有趣值为其子树内size值之积。要求支持左旋右旋操作(就像splay上一样),或是询问某个点的有趣值。
解题思路:
1.先说一下LCT的做法:
注意到每次旋转只会改变两个点(x,y)的size值,然后改变其父亲的有趣值(除以原来y的有趣值,乘以x新的有趣值),所以可以用LCT模拟旋转操作及维护每个点的有趣值。码量极大。而且要点权不为0才行(不然除0就gg了),所以不能过本题。不过还是贴了份代码,以供dalao们参观。
2.线段树做法:
注意到对于平衡树来说不论如何旋转,其中序遍历不会改变,且子树的中序遍历序仍是一段连续的区间,所以我们只要用中序遍历序建线段树,维护每个点的size值,询问时区间求积即可。(注意旋转操作会改变两个点子树的区间,操作时修改即可,详见代码update函数)。
线段树:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=200005,mod=1e9+7;
int T,n,m,tot;
int son[N][2],fa[N],val[N],size[N],mul[N<<2];
int in[N],out[N],pos[N],idx[N];
void dfs(int u,int f)
{
if(!u)return;
fa[u]=f,in[u]=tot+1;
dfs(son[u][0],u);
pos[u]=++tot,idx[tot]=u;
dfs(son[u][1],u);
out[u]=tot;
size[u]=(val[u]+(size[son[u][0]]+size[son[u][1]])%mod)%mod;
}
void build(int k,int l,int r)
{
if(l==r)
{
mul[k]=size[idx[l]];
return;
}
int mid=l+r>>1;
build(k<<1,l,mid),build(k<<1|1,mid+1,r);
mul[k]=1ll*mul[k<<1]*mul[k<<1|1]%mod;
}
void modify(int k,int l,int r,int p,int v)
{
if(l==r)
{
mul[k]=v;
return;
}
int mid=l+r>>1;
if(p<=mid)modify(k<<1,l,mid,p,v);
else modify(k<<1|1,mid+1,r,p,v);
mul[k]=1ll*mul[k<<1]*mul[k<<1|1]%mod;
}
int query(int k,int l,int r,int x,int y)
{
if(x==l&&y==r)return mul[k];
int mid=l+r>>1;
if(y<=mid)return query(k<<1,l,mid,x,y);
else if(x>mid)return query(k<<1|1,mid+1,r,x,y);
else return 1ll*query(k<<1,l,mid,x,mid)*query(k<<1|1,mid+1,r,mid+1,y)%mod;
}
int which(int x)
{
return son[fa[x]][1]==x;
}
void update(int x)
{
in[x]=son[x][0]?in[son[x][0]]:pos[x];
out[x]=son[x][1]?out[son[x][1]]:pos[x];
}
void Rotate(int x)
{
int y=fa[x],z=fa[y],t=which(x);
if(z)son[z][which(y)]=x;
fa[x]=z,fa[y]=x;
son[y][t]=son[x][t^1],son[x][t^1]=y;
if(son[y][t])fa[son[y][t]]=y;
size[x]=size[y];
size[y]=(val[y]+(size[son[y][0]]+size[son[y][1]])%mod)%mod;
update(y),update(x);
modify(1,1,n,pos[x],size[x]),modify(1,1,n,pos[y],size[y]);
}
void clear()
{
tot=0;
memset(son,0,sizeof(son));
memset(fa,0,sizeof(fa));
}
int main()
{
//freopen("splay.in","r",stdin);
//freopen("splay.out","w",stdout);
T=getint();
for(int C=1;C<=T;C++)
{
printf("Case #%d:\n",C);
clear();
int op,x;
n=getint(),m=getint();
for(int i=1;i<=n;i++)
val[i]=getint(),son[i][0]=getint(),son[i][1]=getint();
dfs(1,0);build(1,1,n);
while(m--)
{
op=getint(),x=getint();
if(op==2)printf("%d\n",query(1,1,n,in[x],out[x]));
else
{
x=son[x][op];
if(!x)continue;
Rotate(x);
}
}
}
return 0;
}
LCT:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=200005,p=1e9+7;
int T,n,m;
int root,Son[N][2],Fa[N],val[N],size[N],mul[N];
int son[N][2],fa[N],rev[N],stk[N],tag[N];
void clear()
{
root=1;
memset(Son,0,sizeof(Son));
memset(Fa,0,sizeof(Fa));
memset(val,0,sizeof(val));
memset(size,0,sizeof(size));
memset(son,0,sizeof(son));
memset(fa,0,sizeof(fa));
memset(rev,0,sizeof(rev));
}
int which(int x)
{
return son[fa[x]][1]==x;
}
bool rt(int x)
{
return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
}
void pushdown(int x)
{
if(rev[x])
{
swap(son[x][0],son[x][1]);
if(son[x][0])rev[son[x][0]]^=1;
if(son[x][1])rev[son[x][1]]^=1;
rev[x]=0;
}
if(tag[x]!=1)
{
mul[x]=(ll)mul[x]*tag[x]%p;
if(son[x][0])tag[son[x][0]]=(ll)tag[son[x][0]]*tag[x]%p;
if(son[x][1])tag[son[x][1]]=(ll)tag[son[x][1]]*tag[x]%p;
tag[x]=1;
}
}
void rotate(int x)
{
int y=fa[x],z=fa[y],t=which(x);
if(!rt(y))son[z][which(y)]=x;
fa[x]=z,fa[y]=x;
son[y][t]=son[x][t^1],son[x][t^1]=y;
if(son[y][t])fa[son[y][t]]=y;
}
void splay(int x)
{
int top=0;
stk[++top]=x;
for(int i=x;!rt(i);i=fa[i])stk[++top]=fa[i];
for(int i=top;i;i--)pushdown(stk[i]);
while(!rt(x))
{
if(!rt(fa[x]))
which(x)==which(fa[x])?rotate(fa[x]):rotate(x);
rotate(x);
}
}
void access(int x)
{
for(int y=0;x;y=x,x=fa[x])
{
splay(x),son[x][1]=y;
if(y)fa[y]=x;
}
}
void makeroot(int x)
{
access(x),splay(x);
rev[x]^=1;
}
void link(int x,int y)
{
makeroot(x),fa[x]=y;
}
void cut(int x,int y)
{
makeroot(x),access(y),splay(y);
son[y][0]=fa[x]=0;
}
int Pow(int x,int y)
{
int res=1;
for(;y;y>>=1,x=(ll)x*x%p)
if(y&1)res=(ll)res*x%p;
return res;
}
void update(int u)
{
mul[u]=size[u]=((size[Son[u][0]]+size[Son[u][1]])%p+val[u])%p;
if(Son[u][0])splay(Son[u][0]),mul[u]=(ll)mul[u]*mul[Son[u][0]]%p;
if(Son[u][1])splay(Son[u][1]),mul[u]=(ll)mul[u]*mul[Son[u][1]]%p;
}
void dfs(int u)
{
tag[u]=1;
if(Son[u][0])Fa[Son[u][0]]=fa[Son[u][0]]=u,dfs(Son[u][0]);
if(Son[u][1])Fa[Son[u][1]]=fa[Son[u][1]]=u,dfs(Son[u][1]);
update(u);
}
int Which(int x)
{
return Son[Fa[x]][1]==x;
}
void Rotate(int x)
{
int y=Fa[x],z=Fa[y],t=Which(x);
if(y==root)splay(x),splay(y),root=x;
else Son[z][Which(y)]=x,cut(y,z),link(x,z);
Fa[x]=z,Fa[y]=x;
Son[y][t]=Son[x][t^1],Son[x][t^1]=y;;
if(Son[y][t])cut(x,Son[y][t]),link(y,Son[y][t]),Fa[Son[y][t]]=y;
int tmp=Pow(mul[y],p-2);
update(y),update(x);
tmp=(ll)tmp*mul[x]%p;
if(z)makeroot(root),access(z),splay(z),tag[z]=(ll)tag[z]*tmp%p;
}
int query(int x)
{
splay(x);
return mul[x];
}
int main()
{
//freopen("lx.in","r",stdin);
//freopen("lx.out","w",stdout);
T=getint();
for(int C=1;C<=T;C++)
{
printf("Case #%d:\n",C);
clear();
n=getint(),m=getint();
for(int i=1;i<=n;i++)
val[i]=getint(),Son[i][0]=getint(),Son[i][1]=getint();
dfs(1);
int op,x;
while(m--)
{
op=getint(),x=getint();
if(op<2){if(Son[x][op])Rotate(Son[x][op]);}
else printf("%d\n",query(x));
}
}
return 0;
}