LCT模板(BZOJ2631)

用LCT实现路径加,路径乘,断开及加上一条边(保证是树),查询路径和。

#include <cstdio>
#include <algorithm>
#define l(x) t[x].s[0]
#define r(x) t[x].s[1]
#define f(x) t[x].f
#define lc(x) (r(f(x)) == x)
#define int unsigned int

const int N = 100005, p = 51061;
char op[2];
int n,m,x,y,c,tp,q[N];
struct nd {int v,f,s[2],sm,sz,mu,ad,rv;}t[N];

bool rt(int x) {return l(f(x)) != x && r(f(x)) != x;}
void cal(int x, int m, int a) {
    if(!x) return;
    t[x].v = (t[x].v*m+a)%p, t[x].sm = (t[x].sm*m+a*t[x].sz)%p, t[x].mu = t[x].mu*m%p, t[x].ad = (t[x].ad*m+a)%p;
}

void pu(int x) {t[x].sm = (t[l(x)].sm+t[r(x)].sm+t[x].v)%p, t[x].sz = (t[l(x)].sz+t[r(x)].sz+1)%p;}
void pd(int x) {
    if(t[x].rv) t[x].rv = 0, t[l(x)].rv ^= 1, t[r(x)].rv ^= 1, std::swap(l(x),r(x));
    if(t[x].mu != 1 || t[x].ad) cal(l(x),t[x].mu,t[x].ad),cal(r(x),t[x].mu,t[x].ad);
    t[x].mu = 1, t[x].ad = 0;
}
void rot(int x) {
    int y = f(x), z = f(y), xx = r(y)==x;
    if(!rt(y)) t[z].s[r(z)==y] = x;
    f(x) = z, f(y) = x, f(t[x].s[!xx]) = y;
    t[y].s[xx] = t[x].s[!xx], t[x].s[!xx] = y;
    pu(y);
}
void sp(int x) {
    q[++tp] = x;
    for(int i = x; !rt(i); i = f(i)) q[++tp] = f(i);
    while(tp) pd(q[tp--]);
    for(int y = f(x); !rt(x); rot(x),y=f(x)) if(!rt(y)) {
        if(lc(x)^lc(y)) rot(x); else rot(y);
    }
    pu(x);
}

void acs(int x) {for(int y = 0; x; x = f(x)) sp(x), r(x) = y, pu(y=x);}
void mkrt(int x) {acs(x), sp(x), t[x].rv ^= 1;}
void spli(int x, int y) {mkrt(y), acs(x), sp(x);}
void lk(int x, int y) {mkrt(x), f(x) = y;}
void cut(int x, int y) {mkrt(x), acs(y), sp(y), l(y) = f(x) = 0, pu(y);}

signed main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) t[i].v = t[i].sm = t[i].sz = t[i].mu = 1;
    for(int i = 1; i < n; i++) scanf("%d%d", &x, &y), lk(x,y);
    while(m--) {
        scanf("%s%d%d", op, &x, &y);
        if(op[0] == '+') scanf("%d", &c), spli(x,y), cal(x,1,c);
        else if(op[0] == '-') cut(x,y), scanf("%d%d", &x, &y), lk(x,y);
        else if(op[0] == '*') scanf("%d", &c), spli(x,y), cal(x,c,0);
        else spli(x,y), printf("%d\n", t[x].sm);
    }
    return 0;
}
posted @ 2016-12-26 16:17  Monster_Yi  阅读(334)  评论(1编辑  收藏  举报