诶,卡常数差评
左边的YihAN_Z神犇拿指针版写了一遍就过了,我写的数组版就不过……
有关LCT维护子树信息的讲解可以看这里
用LCT维护链上颜色段数和x的子树内所有的点到x的颜色段数之和,实现题里的操作,查询的时候把根到x的链信息和x的子树信息合并起来就可以出解了
因为就是一个普通的LCT,所以复杂度是n log n 的
这里就说一下每个变量是什么,具体怎么维护就看代码把
LCT上有虚边和实边,实边就是儿子认爹、爹也认儿子,虚边就是儿子认爹爹不认儿子
splay子树即由实边连成的子树
LCT子树即所有在LCT结构中在x以下的子树
fa,son:LCT的父亲儿子结构变量
st,tp:在splay之前下传上边所有标记用的栈
rev,ch:翻转标记和染色标记
siz:LCT上的子树大小
Siz:x的虚子树中在lct上直接连x的部分的大小
SIZ:x的splay上子树大小
v:x的颜色
lv,rv:x的splay子树中最左端和最右端的颜色
cols:x的splay子树在原树上代表的链的颜色段数
coll,colr:x的LCT子树里的所有的点都在原树里走到x的splay子树里最左(右)的点所经过的颜色段数和
Col:x的虚子树中在lct上直接连x的部分在原树上都走到x所经过的颜色段数和
sCol:在计算x的Col的过程中,由于x在原树上的儿子与x颜色相同而没有被计算的颜色段数量
sumsCol:x的splay子树内所有点的sCol值之和
sumCol:x的splay子树内所有点的Col值之和
然后只要在link,access,update和染色的时候好好维护那些量就可以啦!
即使是嘴上说说好像也不是很轻松愉快啊!
可是由于update函数过长,常数过大,跑的挺慢的_-
时隔10个月,我终于贴了一份指针版的代码A了这道题
#include <cstdio>
#include <algorithm>
#define N 100005
#define int long long
using namespace std;
typedef long long LL;
struct Node {
Node *ch[2],*pa;
int dir() { return pa->ch[0]==this ? 0 : pa->ch[1]==this ? 1 : -1; }
int siz,xsiz,rsiz;
int v,lv,rv,coll,colr,cols,Col,sumCol,sCol,sumsCol;
int color_mark;
bool rev_mark;
Node();
void rev();
void color(int);
void pushdown();
void maintain();
void update(Node*,int);
}*null=new Node(),p[N];
Node :: Node():rev_mark(false),color_mark(0),xsiz(0) {
pa=ch[0]=ch[1]=null;
siz=null?1:0;
rsiz=siz;
v=lv=rv=coll=colr=cols=Col=sumCol=sCol=sumsCol=0;
}
void Node :: rev() {
if(this==null) return ;
swap(ch[0],ch[1]);
swap(lv,rv);
swap(coll,colr);
rev_mark=!rev_mark;
return ;
}
void Node :: color(int x) {
if(this==null) return ;
v=lv=rv=color_mark=x;
coll=colr=siz+sumCol+sumsCol;
cols=1;
Col+=sCol;
sumCol+=sumsCol;
sCol=sumsCol=0;
return ;
}
void Node :: pushdown() {
if(rev_mark) {
ch[0]->rev();
ch[1]->rev();
rev_mark=false;
}
if(color_mark) {
ch[0]->color(color_mark);
ch[1]->color(color_mark);
color_mark=0;
}
return ;
}
void Node :: maintain() {
if(this==null) return ;
siz=ch[0]->siz+ch[1]->siz+1;
rsiz=ch[0]->rsiz+ch[1]->rsiz+1+xsiz;
lv=rv=v;
coll=colr=Col+1;
cols=1;
sumCol=Col+ch[0]->sumCol+ch[1]->sumCol;
sumsCol=sCol+ch[0]->sumsCol+ch[1]->sumsCol;
if(ch[0]!=null) {
coll+=ch[0]->coll+ch[0]->cols*(xsiz+1);
int tmp=ch[1]->cols+(ch[1]->lv!=v);
colr+=ch[0]->colr+tmp*ch[0]->rsiz;
if(ch[0]->rv==v) coll-=1+xsiz, colr-=ch[0]->rsiz;
}
if(ch[1]!=null) {
colr+=ch[1]->colr+ch[1]->cols*(xsiz+1);
int tmp=ch[0]->cols+(ch[0]->rv!=v);
coll+=ch[1]->coll+tmp*ch[1]->rsiz;
if(ch[1]->lv==v) colr-=1+xsiz, coll-=ch[1]->rsiz;
}
if(ch[0]!=null)
cols+=ch[0]->cols-(ch[0]->rv==v),
lv=ch[0]->lv;
if(ch[1]!=null)
cols+=ch[1]->cols-(ch[1]->lv==v),
rv=ch[1]->rv;
return ;
}
void Node :: update(Node* o,int k) {
xsiz+=k*o->rsiz;
Col+=k*o->coll;
if(v!=o->lv) Col+=k*o->rsiz;
else sCol+=k*o->rsiz;
return ;
}
void Rotate(Node* o,int d) {
Node* k=o->ch[d^1]; int d2;
o->ch[d^1]=k->ch[d]; k->ch[d]->pa=o;
k->ch[d]=o;
o->maintain(), k->maintain();
if(~(d2=o->dir())) o->pa->ch[d2]=k;
k->pa=o->pa, o->pa=k;
return ;
}
void To_pushdown(Node* o) {
static Node* q[N];
int top=0;
while(~(o->dir())) q[++top]=o, o=o->pa;
q[++top]=o;
while(top) q[top--]->pushdown();
return ;
}
void Splay(Node* o) {
To_pushdown(o);
int d;
while(~(d=o->dir())) {
if(o->pa->dir()==d) Rotate(o->pa->pa,d^1);
Rotate(o->pa,d^1);
}
return ;
}
void Access(Node* o) {
Node* p=null;
while(o!=null) {
Splay(o);
o->update(o->ch[1],1), o->update(p,-1);
o->ch[1]=p, o->maintain();
p=o;
o=o->pa;
}
return ;
}
void Move_to_root(Node* o) {
Access(o), Splay(o);
o->rev();
return ;
}
void Link(Node* x,Node* y) {
Move_to_root(x);
Move_to_root(y);
x->pa=y;
y->update(x,1);
y->maintain();
return ;
}
int n,m,T;
void request(Node* o) {
Access(o), Splay(o);
int ans=o->Col+1,anst=o->xsiz+1,ans2=o->cols;
ans+=anst*(ans2-1);
printf("%.10f\n",1.0*ans/anst);
return ;
}
void release(Node* o) {
Access(o), Splay(o);
o->color(++T);
return ;
}
void recenter(Node* o) {
Move_to_root(o);
o->color(++T);
return ;
}
main() {
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) p[i].color(++T);
for(int i=1;i<n;i++) {
int x,y;
scanf("%lld%lld",&x,&y);
Link(p+x,p+y);
}
Move_to_root(p+1);
while(m--) {
char mode[10];
int x;
scanf("%s%lld",mode,&x);
if(mode[2]=='Q') request(p+x);
else if(mode[2]=='L') release(p+x);
else recenter(p+x);
}
return 0;
}