题目大意:给定一棵树,初始每个点都有一个颜色,支持三种操作:
1.将某个点到根的路径上所有点染上一种新的颜色
2.将某个点到根的路径上所有点染上一种新的颜色,然后把根设为这个点
3.定义一个点的代价为这个点到根路径上颜色的种类数,求某个点子树中所有点代价的平均值
我真是炖了狗了……
容易发现这玩应就是个LCT,操作1就是Access,操作2就是Move_To_Root,代价就是一个点到根路径上的虚边数量+1
我们用LCT模拟上述操作,用线段树维护DFS序维护信息,一旦LCT中出现了虚实边的切换,就在DFS序上对应的子树+1/-1,查询就直接在线段树上查就行了
说起来容易写起来真是日了狗了
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
int n,m;
namespace Tree{
struct edge{
int to,next;
}table[M<<1];
int head[M],tot;
int fa[M][17],dpt[M];
int st[M],ed[M];
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
int LCA(int x,int y)
{
int j;
if(dpt[x]<dpt[y])
swap(x,y);
for(j=16;~j;j--)
if(dpt[fa[x][j]]>=dpt[y])
x=fa[x][j];
if(x==y) return x;
for(j=16;~j;j--)
if(fa[x][j]!=fa[y][j])
x=fa[x][j],y=fa[y][j];
return fa[x][0];
}
int Second_LCA(int x,int y)
{
int j;
for(j=16;~j;j--)
if(dpt[fa[x][j]]>dpt[y])
x=fa[x][j];
return x;
}
}
namespace DFS_Sequence{
struct Segtree{
Segtree *ls,*rs;
long long sum,mark;
void* operator new (size_t)
{
static Segtree mempool[M<<1],*C=mempool;
return C++;
}
void Add(int x,int y,long long val)
{
sum+=(y-x+1)*val;
mark+=val;
}
void Push_Up()
{
sum=ls->sum+rs->sum;
}
void Push_Down(int x,int y)
{
int mid=x+y>>1;
if(mark)
{
ls->Add(x,mid,mark);
rs->Add(mid+1,y,mark);
mark=0;
}
}
void Build_Tree(int x,int y,int a[])
{
int mid=x+y>>1;
if(x==y)
{
sum=a[mid];
return ;
}
(ls=new Segtree)->Build_Tree(x,mid,a);
(rs=new Segtree)->Build_Tree(mid+1,y,a);
Push_Up();
}
void Modify(int x,int y,int l,int r,int val)
{
int mid=x+y>>1;
if(x==l&&y==r)
{
Add(x,y,val);
return ;
}
Push_Down(x,y);
if(r<=mid)
ls->Modify(x,mid,l,r,val);
else if(l>mid)
rs->Modify(mid+1,y,l,r,val);
else
ls->Modify(x,mid,l,mid,val) , rs->Modify(mid+1,y,mid+1,r,val) ;
Push_Up();
}
long long Query(int x,int y,int l,int r)
{
int mid=x+y>>1;
if(x==l&&y==r)
return sum;
Push_Down(x,y);
if(r<=mid)
return ls->Query(x,mid,l,r);
if(l>mid)
return rs->Query(mid+1,y,l,r);
return ls->Query(x,mid,l,mid) + rs->Query(mid+1,y,mid+1,r) ;
}
}*_root=new Segtree;
int root=1;
using namespace Tree;
void Build_Tree()
{
static int a[M];
int i;
for(i=1;i<=n;i++)
a[st[i]]=dpt[i];
_root->Build_Tree(1,n,a);
}
void Modify(int x,int val)
{
if(x==root)
{
_root->Modify(1,n,1,n,val);
return ;
}
int lca=LCA(x,root);
if(lca!=x)
_root->Modify(1,n,st[x],ed[x],val);
else
{
lca=Second_LCA(root,x);
if(st[lca]!=1)
_root->Modify(1,n,1,st[lca]-1,val);
if(ed[lca]!=n)
_root->Modify(1,n,ed[lca]+1,n,val);
}
}
long long Query_Sum(int x)
{
if(x==root)
return _root->Query(1,n,1,n);
long long re=0;
int lca=LCA(x,root);
if(lca!=x)
re+=_root->Query(1,n,st[x],ed[x]);
else
{
lca=Second_LCA(root,x);
if(st[lca]!=1)
re+=_root->Query(1,n,1,st[lca]-1);
if(ed[lca]!=n)
re+=_root->Query(1,n,ed[lca]+1,n);
}
return re;
}
int Query_Size(int x)
{
if(x==root)
return n;
int re=0;
int lca=LCA(x,root);
if(lca!=x)
re+=ed[x]-st[x]+1;
else
{
lca=Second_LCA(root,x);
if(st[lca]!=1)
re+=st[lca]-1;
if(ed[lca]!=n)
re+=n-ed[lca];
}
return re;
}
}
namespace Link_Cut_Tree{
struct abcd{
abcd *ls,*rs,*fa;
bool rev_mark;
abcd();
void _Push_Down();
void Push_Down();
void Reverse();
}*null=new abcd,tree[M];
abcd :: abcd()
{
ls=rs=fa=null;
rev_mark=false;
}
void abcd :: _Push_Down()
{
if(rev_mark)
{
ls->Reverse();
rs->Reverse();
rev_mark=false;
}
}
void abcd :: Push_Down()
{
if(fa->ls==this||fa->rs==this)
fa->Push_Down();
_Push_Down();
}
void abcd :: Reverse()
{
swap(ls,rs);
rev_mark^=1;
}
void Zig(abcd *x)
{
abcd *y=x->fa;
y->ls=x->rs;
x->rs->fa=y;
x->rs=y;
x->fa=y->fa;
if(y==y->fa->ls)
y->fa->ls=x;
else if(y==y->fa->rs)
y->fa->rs=x;
y->fa=x;
}
void Zag(abcd *x)
{
abcd *y=x->fa;
y->rs=x->ls;
x->ls->fa=y;
x->ls=y;
x->fa=y->fa;
if(y==y->fa->ls)
y->fa->ls=x;
else if(y==y->fa->rs)
y->fa->rs=x;
y->fa=x;
}
void Splay(abcd *x)
{
x->Push_Down();
while(x->fa->ls==x||x->fa->rs==x)
{
abcd *y=x->fa,*z=y->fa;
if(x==y->ls)
{
if(y==z->ls)
Zig(y);
Zig(x);
}
else
{
if(y==z->rs)
Zag(y);
Zag(x);
}
}
}
void Find_Min(abcd *x,int val)
{
using namespace DFS_Sequence;
x->_Push_Down();
while(x->ls!=null)
x=x->ls,x->_Push_Down();
Modify(x-tree,val);
}
void Access(abcd *x)
{
abcd *y=null;
while(x!=null)
{
Splay(x);
if(x->rs!=null)
Find_Min(x->rs,1);
if(y!=null)
Find_Min(y,-1);
x->rs=y;
y=x;x=x->fa;
}
}
void Move_To_Root(abcd *x)
{
using namespace DFS_Sequence;
Access(x);
Splay(x);
x->Reverse();
root=x-tree;
}
}
void DFS(int x)
{
using namespace Tree;
using namespace Link_Cut_Tree;
static int T;
int i;
dpt[x]=dpt[fa[x][0]]+1;
st[x]=++T;
for(i=1;i<=16;i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(i=head[x];i;i=table[i].next)
if(table[i].to!=fa[x][0])
{
fa[table[i].to][0]=x;
DFS(table[i].to);
tree[table[i].to].fa=&tree[x];
}
ed[x]=T;
}
int main()
{
using namespace Tree;
using namespace DFS_Sequence;
using namespace Link_Cut_Tree;
int i,x,y;
char p[10];
cin>>n>>m;
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
Add(x,y);Add(y,x);
}
DFS(1);
Build_Tree();
for(i=1;i<=m;i++)
{
scanf("%s%d",p+1,&x);
switch(p[3])
{
case 'L':
Access(&tree[x]);
break;
case 'C':
Move_To_Root(&tree[x]);
break;
case 'Q':
printf("%.10lf\n",(double)Query_Sum(x)/Query_Size(x));
break;
}
}
return 0;
}