BZOJ 4530 [Bjoi2014]大融合 LCT维护子树信息

题目大意:给出n个点,定义一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量,要求支持两个操作:加边,询问边的负载。保证加边不会出现环。

暴力用LCT维护子树信息。

LCT维护子树信息(子树信息LCT) LCT维护边权(边权LCT) 知识点讲解

与普通LCT的区别主要在于maintain函数(更新节点信息)和update函数(虚实边转换时更新信息,普通LCT没有)

siz表示正常Splay的size(然而在这道题里并没有什么卵用)
rsiz(real_size)表示LCT子树的size和(rsiz=ch[0]->rsiz+ch[1]->rsiz+xsiz+1,注意可能会包括父亲的rsiz)
xsiz(虚_size)表示与当前点连虚边的儿子的LCT子树size和(用于更新rsiz)

#include <cstdio>
#include <algorithm>
#define N 100005
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;
    bool rev_mark;
    Node();
    void rev();
    void pushdown();
    void maintain();
    void update(Node*,int);
}*null=new Node(),p[N];
Node :: Node():rev_mark(false),xsiz(0) {
    pa=ch[0]=ch[1]=null;
    siz=null?1:0;
    rsiz=siz;
}
void Node :: rev() {
    rev_mark=!rev_mark;
    swap(ch[0],ch[1]);
    return ;
}
void Node :: pushdown() {
    if(rev_mark) {
        ch[0]->rev();
        ch[1]->rev();
        rev_mark=false;
    }
    return ;
}
void Node :: maintain() {
    siz=ch[0]->siz+ch[1]->siz+1;
    rsiz=ch[0]->rsiz+ch[1]->rsiz+1+xsiz;
    return ;
}
void Node :: update(Node* o,int k) {
    xsiz+=k*o->rsiz;
    rsiz+=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);
    return ;
}
LL query(Node* x,Node* y) {
    Move_to_root(x);
    Access(y), Splay(x);
    return (LL)(x->xsiz+1)*(y->rsiz-x->xsiz-1);
}
int n,T;
int main() {
    scanf("%d",&n);
    for(scanf("%d",&T);T;T--) {
        char mode[3];
        int x,y;
        scanf("%s%d%d",mode,&x,&y);
        if(mode[0]=='A') Link(p+x,p+y);
        else printf("%lld\n",query(p+x,p+y));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值