您的位置:首页 > 运维架构

BZOJ 3779 重组病毒 LCT维护子树信息

2017-04-07 09:52 393 查看
题目大意:给定一棵树,要求支持:将某个点到根的路径染色;换根后将原来的根到现在的根的路径染色;求某个点的子树到根的平均颜色段数

比较麻烦的LCT维护子树信息

变量名是照neither_nor神犇抄的..意义相同,链接

因为要计算子树到根的平均颜色段数,所以要维护子树到(子树的)根的颜色段数和(Col),Splay在原树中代表的链的颜色段数(cols),子树size(rsiz)。

其实就是把子树到当前根的颜色段数和分成子树到子树根和子树根到当前根两部分。将想要查询的子树根Access+Splay后,Col即为子树内颜色段数和,cols即为子树根到当前根。

而要维护Col,就要维护coll/colr,sumCol,sCol,sumCol

具体的更新关系为:

coll->Col (update)

colr->coll (rev)

sumCol->coll/colr (color)

sCol->Col / sumsCol->sumCol (color)

Col->coll/colr (maintain)

Col->sumCol / sCol->sumsCol (maintain)

coll->colr / colr->coll (maintain)

将变量整理后,

正常Splay信息:siz,v,lv,rv,cols

虚子树信息:xsiz,Col,sCol

LCT子树信息:rsiz,coll,colr,sumCol,sumsCol

#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; }
///Basic Splay varieties
int siz,xsiz,rsiz,v,lv,rv,cols;
///color information
int coll,colr,Col,sumCol,sCol,sumsCol;
///mark
int color_mark;
bool rev_mark;
///function
Node();
void rev();
void color(int);
void pushdown();
void maintain();
void update(Node*,int);
}*null=new Node(),p
;
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;
cols=1;
coll=colr=siz+sumCol+sumsCol;
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;
cols=1;
coll=colr=Col+1;
sumCol=Col+ch[0]->sumCol+ch[1]->sumCol;
sumsCol=sCol+ch[0]->sumsCol+ch[1]->sumsCol;
if(ch[0]!=null) {
cols+=ch[0]->cols-(ch[0]->rv==v);
lv=ch[0]->lv;
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) {
cols+=ch[1]->cols-(ch[1]->lv==v),
rv=ch[1]->rv;
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;
}
return ;
}
void Node :: update(Node* o,int k) {
xsiz+=k*o->rsiz, rsiz+=k*o->rsiz;
Col+=k*o->coll, sumCol+=k*o->coll, coll+=k*o->coll, colr+=k*o->coll;
if(v!=o->lv) Col+=k*o->rsiz, sumCol+=k*o->rsiz, coll+=k*o->rsiz, colr+=k*o->rsiz;
else sCol+=k*o->rsiz, sumsCol+=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
;
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);
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: