上周看Lytning(鄙校一队某大佬)开了一个LCT的专题,里面有这个题,正好我也没怎么写过LCT维护子树的题,就决定拿这个题开刀。
先来说说LCT维护子树的大致思路,LCT里的轻边在Splay里都是只有儿子指向父亲但是父亲不指向儿子的虚边,如果维护的是树链,只用维护Splay里的实边,但是维护子树的话只要把每个节点的虚边也维护一下就行了。
我之前只写过不带修改的子树维护,不带修改只要把虚子树信息向上更新即可,但是要修改的话,就要有标记下放,标记下方的时候要对所有虚子树下放标记。如果用一个线性结构维护虚子树,就会被菊花图卡死,于是就想到用一个平衡树来维护所有的虚子树。这个就是传说中的Toptree。
但是我开了这个题之后,发现我进了一个无底洞,写题3小时,debug一星期,本来以为只是要维护的变量多了点而已,但是写的时候发现有一些细节不是很好处理。说一下主要遇到的几个问题,最开始遇到的问题是函数调用,前面的函数要调后面的函数,虽然我觉得这样不是很优雅,但是想了想也没啥好的解决办法。遇到的第二个问题,而是蒙蔽我时间最长的一个问题,我平衡树用的是Treap,但是我没写过标记下放的Treap,于是我在删节点的时候写残了,这个真是坑死我了。还有一个就是Splay和LCT的access(expose)过程中的标记下放,我之前Splay的标记下放都是边转边下放,网上其他大佬们的代码都是从根一路下放下来再转上去,可能我的写法是邪教吧,之前没出过问题,但是这个题就是不对,这个问题其实我现在还没明白为什么不对,希望有大佬知道的可以告诉我……
一些闲话,比如说STL的stack真的血慢,还有就是我的数据结构都是指针写的,虽然经常被学长喷卡内存啥的,但是BZOJ是32位机不怕嘿嘿嘿。
最后奉上我又臭又长的代码,基本上是照着mhy的代码改的
#include
using namespace std;
const int MAXN = 100005, INF = 0x7fffffff;
struct Treap
{
struct Node
{
int idx, pr, siz, maxv, minv, sumv, add, val;
bool lazy;
Node *child[2];
inline int cmp(int) const;
inline void maintain();
inline void change_val(int);
inline void add_val(int);
inline void push_down();
}pool[MAXN], *nil, *alloc;
Node* new_Node(int);
void init();
void rotate(Node*&, int);
void insert(Node*, Node*&);
void erase(int, Node*&);
void debug(Node*);
}treap;
struct Splay_tree
{
struct Node
{
int idx;
Treap::Node *root;
Node *child[2], *parent;
inline bool isroot() const;
inline void maintain();
inline void tree_change(int);
inline void chain_change(int);
inline void tree_add(int);
inline void chain_add(int);
inline void reverse();
inline void push_down();
inline void insert(Node*);
inline void erase(Node*);
}*nil, pool[MAXN], *alloc;
Node* new_Node(int);
void init();
Node* find(Node*);
void update(Node*);
void rotate(Node*);
void splay(Node*);
Node* prec(Node*);
};
struct Record
{
int key, cadd, tadd, cval, tval, csiz, tsiz,
cmax, tmax, cmin, tmin, csum, tsum;
bool flip, clazy, tlazy;
Treap::Node* tr;
Splay_tree::Node* sp;
}rec[MAXN], *alloc = rec;
int new_Record(int key)
{
Record* ret = alloc++;
ret->csiz = 1;
ret->key = ret->cmax = ret->cmin = ret->csum = key;
ret->tmax = -INF;
ret->tmin = INF;
ret->tsum = ret->tsiz = ret->cadd = ret->tadd = 0;
ret->flip = ret->clazy = ret->tlazy = false;
return ret - rec;
}
inline int Treap::Node::cmp(int v) const
{
if (v == idx) return -1;
else return v < idx ? 0 : 1;
}
inline void Treap::Node::maintain()
{
siz = rec[idx].csiz + rec[idx].tsiz;
maxv = max(rec[idx].cmax, rec[idx].tmax);
minv = min(rec[idx].cmin, rec[idx].tmin);
sumv = rec[idx].csum + rec[idx].tsum;
for (int i = 0; i < 2; i++)
{
siz += child[i]->siz;
maxv = max(maxv, child[i]->maxv);
minv = min(minv, child[i]->minv);
sumv += child[i]->sumv;
}
}
inline void Treap::Node::change_val(int v)
{
if (idx == 0) return;
add = 0;
lazy = true;
val = maxv = minv = v;
sumv = siz * v;
}
inline void Treap::Node::add_val(int v)
{
if (idx == 0) return;
add += v;
maxv += v, minv += v;
sumv += siz * v;
}
inline void Treap::Node::push_down()
{
if (lazy)
{
rec[idx].sp->tree_change(val);
rec[idx].sp->chain_change(val);
child[0]->change_val(val);
child[1]->change_val(val);
lazy = false;
}
if (add)
{
rec[idx].sp->tree_add(add);
rec[idx].sp->chain_add(add);
child[0]->add_val(add);
child[1]->add_val(add);
add = 0;
}
}
Treap::Node* Treap::new_Node(int idx)
{
Node* ret = alloc++;
ret->idx = idx;
ret->pr = rand();
ret->siz = 1;
ret->maxv = ret->minv = ret->sumv = rec[idx].key;
ret->add = ret->val = 0;
ret->lazy = false;
ret->child[0] = ret->child[1] = nil;
return ret;
}
void Treap::init()
{
alloc = pool;
nil = alloc++;
nil->idx = nil->pr = 0;
nil->siz = nil->sumv = 0;
nil->maxv = -INF;
nil->minv = INF;
}
void Treap::rotate(Node* &x, int dir)
{//0 : 1 ? zag : zig
Node* y = x->child[dir ^ 1];
x->push_down(), y->push_down();
x->child[dir ^ 1] = y->child[dir];
y->child[dir] = x;
x->maintain(), y->maintain();
x = y;
}
void Treap::insert(Node* temp, Node* &curr)
{
if (curr == nil) curr = temp;
else
{
curr->push_down();
int dir = (temp->idx < curr->idx ? 0 : 1);
insert(temp, curr->child[dir]);
if (curr->child[dir]->pr > curr->pr)
rotate(curr, dir ^ 1);
}
curr->maintain();
}
void Treap::erase(int idx, Node* &curr)
{
curr->push_down();
int d = curr->cmp(idx);
if (d == -1)
{
if (curr->child[0] == nil) curr = curr->child[1];
else if (curr->child[1] == nil) curr = curr->child[0];
else
{
int dir = (curr->child[0]->pr > curr->child[1]->pr ? 1 : 0);
rotate(curr, dir);
erase(idx, curr->child[dir]);
curr->maintain();
}
}
else
{
erase(idx, curr->child[d]);
curr->maintain();
}
}
void Treap::debug(Node* curr)
{
if (curr == nil) return;
curr->push_down();
debug(curr->child[0]);
debug(curr->child[1]);
}
inline bool Splay_tree::Node::isroot() const
{
if (this->parent->idx == 0) return true;
return this->parent->child[0] != this &&
this->parent->child[1] != this;
}
inline void Splay_tree::Node::maintain()
{
rec[idx].csiz = 1;
rec[idx].cmax = rec[idx].cmin = rec[idx].csum = rec[idx].key;
rec[idx].tsiz = root->siz;
rec[idx].tmax = root->maxv;
rec[idx].tmin = root->minv;
rec[idx].tsum = root->sumv;
for (int i = 0; i < 2; i++)
{
rec[idx].csiz += rec[child[i]->idx].csiz;
rec[idx].cmax = max(rec[idx].cmax, rec[child[i]->idx].cmax);
rec[idx].cmin = min(rec[idx].cmin, rec[child[i]->idx].cmin);
rec[idx].csum += rec[child[i]->idx].csum;
rec[idx].tsiz += rec[child[i]->idx].tsiz;
rec[idx].tmax = max(rec[idx].tmax, rec[child[i]->idx].tmax);
rec[idx].tmin = min(rec[idx].tmin, rec[child[i]->idx].tmin);
rec[idx].tsum += rec[child[i]->idx].tsum;
}
}
inline void Splay_tree::Node::tree_change(int v)
{
if (rec[idx].tsiz == 0) return;
rec[idx].tadd = 0;
rec[idx].tlazy = true;
rec[idx].tval = v;
rec[idx].tmax = rec[idx].tmin = v;
rec[idx].tsum = rec[idx].tsiz * v;
root->change_val(v);
}
inline void Splay_tree::Node::chain_change(int v)
{
if (idx == 0) return;
rec[idx].cadd = 0;
rec[idx].clazy = true;
rec[idx].key = rec[idx].cval = rec[idx].cmax = rec[idx].cmin = v;
rec[idx].csum = rec[idx].csiz * v;
}
inline void Splay_tree::Node::tree_add(int v)
{
if (rec[idx].tsiz == 0) return;
rec[idx].tadd += v;
rec[idx].tmax += v, rec[idx].tmin += v;
rec[idx].tsum += rec[idx].tsiz * v;
root->add_val(v);
}
inline void Splay_tree::Node::chain_add(int v)
{
if (idx == 0) return;
rec[idx].key += v;
rec[idx].cadd += v;
rec[idx].cmax += v, rec[idx].cmin += v, rec[idx].csum += rec[idx].csiz * v;
}
inline void Splay_tree::Node::reverse()
{
swap(child[0], child[1]);
rec[idx].flip = !rec[idx].flip;
}
inline void Splay_tree::Node::push_down()
{
for (int i = 0; i < 2; i++)
{
if (rec[idx].tlazy) child[i]->tree_change(rec[idx].tval);
if (rec[idx].tadd) child[i]->tree_add(rec[idx].tadd);
if (rec[idx].clazy) child[i]->chain_change(rec[idx].cval);
if (rec[idx].cadd) child[i]->chain_add(rec[idx].cadd);
if (rec[idx].flip) child[i]->reverse();
}
rec[idx].cadd = rec[idx].tadd = 0;
rec[idx].flip = rec[idx].clazy = rec[idx].tlazy = false;
}
inline void Splay_tree::Node::insert(Node* x)
{
treap.insert(rec[x->idx].tr, root);
}
inline void Splay_tree::Node::erase(Node* x)
{
treap.erase(x->idx, root);
rec[x->idx].tr->child[0] = rec[x->idx].tr->child[1] = treap.nil;
}
Splay_tree::Node* Splay_tree::new_Node(int key)
{
Node* ret = alloc++;
ret->idx = new_Record(key);
rec[ret->idx].tr = treap.new_Node(ret->idx);
rec[ret->idx].sp = ret;
ret->root = treap.nil;
ret->child[0] = ret->child[1] = ret->parent = nil;
return ret;
}
void Splay_tree::init()
{
alloc = pool;
nil = alloc++;
nil->idx = new_Record(0);
rec[nil->idx].csiz = rec[nil->idx].tsiz = 0;
rec[nil->idx].cmax = rec[nil->idx].tmax = -INF;
rec[nil->idx].cmin = rec[nil->idx].tmin = INF;
treap.init();
rec[nil->idx].tr = nil->root = treap.nil;
}
Splay_tree::Node* Splay_tree::find(Node* curr)
{
while (!curr->isroot()) curr = curr->parent;
return curr;
}
void Splay_tree::update(Node* curr)
{
if (!curr->isroot()) update(curr->parent);
curr->push_down();
}
void Splay_tree::rotate(Node* x)
{//0 : 1 ? zag : zig
Node* y = x->parent;
y->push_down(), x->push_down();
int dir = (y->child[0] == x ? 1 : 0);
y->child[dir ^ 1] = x->child[dir];
x->child[dir]->parent = y;
x->parent = y->parent;
if (!y->isroot())
{
if (y == y->parent->child[0])
y->parent->child[0] = x;
else y->parent->child[1] = x;
}
x->child[dir] = y;
y->parent = x;
y->maintain();
}
void Splay_tree::splay(Node* x)
{
Node* temp = find(x);
if (temp->parent != nil) temp->parent->erase(temp);
update(x);
while (!x->isroot())
{
Node *y = x->parent, *z = y->parent;
if (!y->isroot())
{
if ((z->child[0] == y) == (y->child[0] == x))
rotate(y);
else rotate(x);
}
rotate(x);
}
x->maintain();
if (x->parent != nil) x->parent->insert(x);
}
Splay_tree::Node* Splay_tree::prec(Node* curr)
{
splay(curr);
Node* ret = curr->child[0];
while (ret != nil && ret->child[1] != nil)
{
ret = ret->child[1];
ret->push_down();
}
return ret;
}
int n, m, r;
struct Link_Cut_tree
{
Splay_tree tree;
typedef Splay_tree::Node Node;
Node* root[MAXN];
void init(int* value, int n)
{
tree.init();
for (int i = 1; i <= n; i++)
root[i] = tree.new_Node(value[i]);
}
void update(Node* curr)
{
if (curr->parent != tree.nil) update(curr->parent);
curr->push_down();
}
void access(int x)
{
update(root[x]);
for (Node *curr = root[x], *last = tree.nil;
curr != tree.nil; last = curr, curr = curr->parent)
{
tree.splay(curr);
if (last != tree.nil) curr->erase(last);
if (curr->child[1] != tree.nil) curr->insert(curr->child[1]);
curr->child[1] = last;
curr->maintain();
}
tree.splay(root[x]);
}
int find(int x)
{
access(x);
Node* ret = root[x];
while (ret->child[0] != tree.nil)
ret = ret->child[0];
return ret - tree.nil;
}
void be_root(int x)
{
access(x);
root[x]->reverse();
}
void cut(int x)
{
access(x);
root[x]->child[0]->parent = tree.nil;
root[x]->child[0] = tree.nil;
root[x]->maintain();
}
void link(int x, int y)
{
if (y == 0) return;
be_root(x);
access(y);
root[x]->parent = root[y];
root[y]->child[1] = root[x];
root[y]->maintain();
}
void tree_change(int x, int v)
{
access(x);
Node* y = tree.prec(root[x]);
if (y != tree.nil) tree.splay(y);
root[x]->tree_change(v);
root[x]->chain_change(v);
if (y != tree.nil) y->maintain();
}
void chain_change(int x, int y, int v)
{
be_root(x);
access(y);
root[y]->chain_change(v);
}
int tree_min(int x)
{
access(x);
Node* y = tree.prec(root[x]);
if (y != tree.nil) tree.splay(y);
return min(rec[root[x]->idx].cmin, rec[root[x]->idx].tmin);
}
int tree_max(int x)
{
access(x);
Node* y = tree.prec(root[x]);
if (y != tree.nil) tree.splay(y);
return max(rec[root[x]->idx].cmax, rec[root[x]->idx].tmax);
}
void tree_add(int x, int v)
{
access(x);
Node* y = tree.prec(root[x]);
if (y != tree.nil) tree.splay(y);
root[x]->tree_add(v);
root[x]->chain_add(v);
if (y != tree.nil) y->maintain();
}
void chain_add(int x, int y, int v)
{
be_root(x);
access(y);
root[y]->chain_add(v);
}
int chain_min(int x, int y)
{
be_root(x);
access(y);
return rec[root[y]->idx].cmin;
}
int chain_max(int x, int y)
{
be_root(x);
access(y);
return rec[root[y]->idx].cmax;
}
void change_parent(int x, int y)
{
access(x);
Node* z = tree.prec(root[x]);
cut(x);
if (find(y) == x) link(x, z - tree.nil);
else link(x, y);
}
int chain_sum(int x, int y)
{
be_root(x);
access(y);
return rec[root[y]->idx].csum;
}
int tree_sum(int x)
{
access(x);
Node* y = tree.prec(root[x]);
if (y != tree.nil) tree.splay(y);
return rec[root[x]->idx].csum + rec[root[x]->idx].tsum;
}
}lct;
struct Edge
{
int u, v;
}edges[MAXN];
int value[MAXN];
inline char getch()
{
static const int siz = 1 << 15;
static char buffer[siz], *s = buffer, *t = buffer;
if (s == t) s = buffer, t = s + fread(buffer, 1, siz, stdin);
return s == t ? 0 : *(s++);
}
inline int read(int& res)
{
res = 0;
char ch;
do
{
ch = getch();
if (ch == 0) return -1;
} while (!isdigit(ch) && ch != '-');
int sgn = 1;
if (ch == '-')
{
sgn = -1;
ch = getch();
}
do
{
res = res * 10 + ch - '0';
ch = getch();
} while (isdigit(ch));
res *= sgn;
return 1;
}
int main()
{
read(n), read(m);
for (int i = 1; i < n; i ++)
read(edges[i].u), read(edges[i].v);
for (int i = 1; i <= n; i ++)
read(value[i]);
lct.init(value, n);
for (int i = 1; i < n; i ++)
lct.link(edges[i].u, edges[i].v);
read(r);
while (m--)
{
int k, x, y, z;
read(k);
if (k == 0)
{
read(x), read(y);
lct.be_root(r);
lct.tree_change(x, y);
}
else if (k == 1) read(r);
else if (k == 2)
{
read(x), read(y), read(z);
lct.chain_change(x, y, z);
}
else if (k == 3)
{
read(x);
lct.be_root(r);
printf("%d\n", lct.tree_min(x));
}
else if (k == 4)
{
read(x);
lct.be_root(r);
printf("%d\n", lct.tree_max(x));
}
else if (k == 5)
{
read(x), read(y);
lct.be_root(r);
lct.tree_add(x, y);
}
else if (k == 6)
{
read(x), read(y), read(z);
lct.chain_add(x, y, z);
}
else if (k == 7)
{
read(x), read(y);
printf("%d\n", lct.chain_min(x, y));
}
else if (k == 8)
{
read(x), read(y);
printf("%d\n", lct.chain_max(x, y));
}
else if (k == 9)
{
read(x), read(y);
lct.be_root(r);
lct.change_parent(x, y);
}
else if (k == 10)
{
read(x), read(y);
printf("%d\n", lct.chain_sum(x, y));
}
else
{
read(x);
lct.be_root(r);
printf("%d\n", lct.tree_sum(x));
}
}
return 0;
}