[SP16580 QTREE7 - Query on a tree VII]

洛谷传送门

题目描述

You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are numbered from 1 1 to n. Each node has a color, white or black, and a weight. We will ask you to perfrom some instructions of the following form:

0 0 u: ask for the maximum weight among the nodes which are connected to u, two nodes are connected if all the node on the path from u u to v (inclusive u u and v) have a same color.
1 1 u: toggle the color of u u (that is, from black to white, or from white to black).
2 u u w: change the weight of u u to w.

输入输出格式

输入格式:

The first line contains a number n denoted how many nodes in the tree (1n105) ( 1 ≤ n ≤ 10 5 ) . The next n1 n − 1 lines, each line has two numbers (u,v) ( u , v ) describe a edge of the tree (1u,vn) ( 1 ≤ u , v ≤ n ) . The next 2 2 lines, each line contains n number, the first line is the initial color of each node (0 or 1) ( 0   o r   1 ) , and the second line is the initial weight, let’s say Wi W i , of each node (|Wi|109) ( | W i | ≤ 10 9 ) . The next line contains a number m denoted how many operations we are going to process (1m105) ( 1 ≤ m ≤ 10 5 ) . The next m lines, each line describe a operation (t,u) ( t , u ) as we mentioned above (0t2,1un,|w|109) ( 0 ≤ t ≤ 2 , 1 ≤ u ≤ n , | w | ≤ 10 9 ) .

输出格式:

For each query operation, output the corresponding result.

输入输出样例

输入样例#1:
5
1 2
1 3
1 4
1 5
0 1 1 1 1
1 2 3 4 5
3
0 1
1 1
0 1
1 2
输出样例#1:
1
5
输入样例#2:
7
1 2
1 3
2 4
2 5
3 6
3 7
0 0 0 0 0 0 0
1 2 3 4 5 6 7
4
0 1
1 1
0 2
0 3
输出样例#2:
7
5
7

解题分析

Qtree6 Q t r e e 6 一样, 我们可以建立黑白两棵树, 连通块的最大值我们用一个 multiset m u l t i s e t 维护, 每次在 access a c c e s s 的时候插入/删除信息即可。

不过multiset很坑的一点是如果 erase e r a s e 一个值的话会将所有那个值 erase e r a s e 掉, 所以需要先 find f i n d 到指针。博主莫名其妙WA了很多次…

代码如下:

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <set>
#include <limits.h>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 100010
#define dad tree[typ][now].fat
#define ls tree[typ][now].son[0]
#define rs tree[typ][now].son[1]
bool fu;
template <class T>
IN void in (T &x)
{
    fu = false; x = 0; R char c = gc;
    W (!isdigit(c))
    { if(c == '-') fu = true; c = gc;}
    W (isdigit(c))
    x = (x << 1) + (x << 3) + c - 48, c = gc;
    if(fu) x = -x;
}
namespace LCT
{
    int fat[MX], dot, q, cnt, head[MX], col[MX];
    struct Edge
    {
        int to, nex;
    }edge[MX << 1];
    IN void addedge(const int &from, const int &to)
    {edge[++cnt] = {to, head[from]}, head[from] = cnt;}
    struct Node
    {
        int son[2], fat, val, mx;
        std::multiset <int> vir;
    }tree[2][MX];
    IN bool get(const int &typ, const int &now) {return tree[typ][dad].son[1] == now;}
    IN bool nroot(const int &typ, const int &now) {return tree[typ][dad].son[1] == now || tree[typ][dad].son[0] == now;}
    IN void pushup(const int &typ, const int &now) 
    {
        tree[typ][now].mx = std::max(tree[typ][ls].mx, std::max(tree[typ][now].val, tree[typ][rs].mx));
        if(!tree[typ][now].vir.empty()) tree[typ][now].mx = std::max(tree[typ][now].mx, *tree[typ][now].vir.rbegin());//注意rbegin和end的区别
    }
    IN void rotate(const int &typ, const int &now)
    {
        R bool dir = get(typ, now);
        R int fa = dad, grand = tree[typ][fa].fat;
        tree[typ][fa].son[dir] = tree[typ][now].son[dir ^ 1];
        tree[typ][tree[typ][now].son[dir ^ 1]].fat = fa;
        if(nroot(typ, fa)) tree[typ][grand].son[get(typ, fa)] = now;
        tree[typ][now].fat = grand;
        tree[typ][now].son[dir ^ 1] = fa;
        tree[typ][fa].fat = now;
        pushup(typ, fa);
    }
    IN void splay(const int &typ, R int now)
    {
        R int fa, grand;
        W (nroot(typ, now))
        {
            fa = dad, grand = tree[typ][fa].fat;
            if(nroot(typ, fa)) rotate(typ, (get(typ, now) == get(typ, fa) ? fa : now));
            rotate(typ, now);
        }
        pushup(typ, now);
    }
    IN void access(const int &typ, R int now)
    {
        for (R int x = 0; now; x = now, now = dad)
        {
            splay(typ, now);
            if(rs) tree[typ][now].vir.insert(tree[typ][rs].mx);
            if(x) tree[typ][now].vir.erase(tree[typ][now].vir.find(tree[typ][x].mx));
            rs = x; pushup(typ, now);
        }
    }
    IN int findroot(const int &typ, R int now)
    {
        access(typ, now), splay(typ, now);
        W (ls) now = ls;
        splay(typ, now);
        return now;
    }
    IN void link(const int &typ, const int &now)
    {
        splay(typ, now);
        R int fa = dad = fat[now];
        access(typ, fa), splay(typ, fa);
        tree[typ][fa].son[1] = now; pushup(typ, fa);
    }
    IN void cut (const int &typ, const int &now)
    {
        access(typ, now), splay(typ, now);
        ls = tree[typ][ls].fat = 0;
        pushup(typ, now);
    }
    void DFS(const int &now)
    {
        for (R int i = head[now]; i; i = edge[i].nex)
        {
            if(edge[i].to == fat[now]) continue;
            fat[edge[i].to] = now;
            DFS(edge[i].to);
        }
        link(col[now], now);
    }
    IN void modify(const int &typ, const int &now, const int &del)
    {
        access(typ, now), splay(typ, now);
        tree[typ][now].val = del;
        pushup(typ, now);
    }
}
using namespace LCT;
int main(void)
{
    int a, b, c, rt;
    in(dot);
    for (R int i = 1; i < dot; ++i)
    in(a), in(b), addedge(a, b), addedge(b, a);
    for (R int i = 1; i <= dot; ++i) in(col[i]);
    for (R int i = 0; i <= dot; ++i) tree[0][i].mx = tree[1][i].mx = -INT_MAX;//有负数, 所以要足够小
    for (R int i = 1; i <= dot; ++i) in(tree[col[i]][i].val), tree[col[i] ^ 1][i].val = tree[col[i]][i].val;//初始化时两棵树都要保存
    fat[1] = dot + 1; tree[0][dot + 1].mx = tree[1][dot + 1].mx = -INT_MAX;
    DFS(1);
    in(q);
    W (q--)
    {
        in(a), in(b);
        switch (a)
        {
            case 0:
            {
                rt = findroot(col[b], b);
                printf("%d\n", tree[col[b]][tree[col[b]][rt].son[1]].mx);
                break;
            }
            case 1:
            {
                cut(col[b], b);
                col[b] ^= 1;
                link(col[b], b);
                break;
            }
            case 2:
            {
                in(c);
                modify(col[b], b, c);
                modify(col[b] ^ 1, b, c); 
                break;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值