bzoj3306: 树 LCT

bzoj3306: 树

Description

给定一棵大小为 n 的有根点权树,支持以下操作:
  • 换根
  • 修改点权
 • 查询子树最小值

Input

  第一行两个整数 n, Q ,分别表示树的大小和操作数。
  接下来n行,每行两个整数f,v,第i+1行的两个数表示点i的父亲和点i的权。保证f < i。如 果f = 0,那么i为根。输入数据保证只有i = 1时,f = 0。
  接下来 m 行,为以下格式中的一种:
  • V x y表示把点x的权改为y
  • E x 表示把有根树的根改为点 x
  • Q x 表示查询点 x 的子树最小值

Output

  对于每个 Q ,输出子树最小值。

Sample Input

3 7
0 1
1 2
1 3
Q 1
V 1 6
Q 1
V 2 5
Q 1
V 3 4
Q 1
Sample Output
1
2
3
4
HINT
  对于 100% 的数据:n, Q ≤ 10^5。

分析

换根搞子树有个神仙操作,先转有根树,然后考虑换的根u和子树根v关系。如果 l c a ( u , v ) v 不会有任何影响,否则就是挖掉子树根在根方向上的儿子的子树的所有节点。用倍增+线段树搞就可以了。
然而,会LCT就是不讲道理的。
LCT+set+维护子树信息。
妥妥的。
跑得慢?你需要一个三级高速缓存优化吗?

代码

#include<cstdio>
#include<set>
#include<algorithm>
const int N = 1e5 + 10; using std::min;
int ri() {
    char ch = getchar(); int x = 0; for(;ch < '0' || ch > '9'; ch = getchar()) ;
    for(;ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) - '0' + ch; return x;
}
int rc() {
    char ch = getchar(); for(;ch != 'V' && ch != 'Q' && ch != 'E'; ch = getchar()) ;
    return ch == 'V' ? 1 : (ch == 'E' ? 2 : 3);
}
std::multiset<int>s[N]; int r[N], fa[N], ch[N][2], mn[N], v[N], st[N], tp;
void Era(int u, int v) {s[u].erase(s[u].find(v));}
bool wh(int p) {return ch[fa[p]][1] == p;}
bool Ir(int p) {return ch[fa[p]][0] != p && ch[fa[p]][1] != p;}
void Down(int p) {
    if(r[p]) std::swap(ch[p][0], ch[p][1]), r[ch[p][0]] ^= 1, r[ch[p][1]] ^= 1, r[p] = 0;
}
void Up(int p) {mn[p] = min(min(mn[ch[p][0]], mn[ch[p][1]]), *(s[p].begin()));}
void Rotate(int p) {
    int f = fa[p], g = fa[f], c = wh(p);
    if(!Ir(f)) ch[g][wh(f)] = p; fa[p] = g;
    ch[f][c] = ch[p][c ^ 1]; if(ch[f][c]) fa[ch[f][c]] = f;
    ch[p][c ^ 1] = f; fa[f] = p; Up(f);
}
void Splay(int p) {
    st[tp = 1] = p; for(int i = p; !Ir(i); i = fa[i]) st[++tp] = fa[i];
    for(int i = tp; i; --i) Down(st[i]);
    for(;!Ir(p); Rotate(p)) if(!Ir(fa[p])) Rotate(wh(fa[p]) == wh(p) ? fa[p] : p);
    Up(p);
}
void Access(int p) {
    for(int pr = 0; p; p = fa[pr = p]) {
        Splay(p); if(pr) Era(p, mn[pr]);
        if(ch[p][1]) s[p].insert(mn[ch[p][1]]); 
        ch[p][1] = pr; Up(p);
    }
}
void Get(int u) {Access(u); Splay(u);}
int main() {
    int n = ri(), m = ri(); mn[0] = 1e9;
    for(int i = 1;i <= n; ++i) fa[i] = ri(), s[i].insert(v[i] = ri());
    for(int i = n; i; --i) Up(i), s[fa[i]].insert(mn[i]);
    for(;m--;) {
        int op = rc(), x = ri();
        if(op == 1) Get(x), Era(x, v[x]), s[x].insert(v[x] = ri()), Up(x);
        if(op == 2) Get(x), r[x] ^= 1;
        if(op == 3) Get(x), printf("%d\n", *(s[x].begin()));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/80784962