0
点赞
收藏
分享

微信扫一扫

HDU 4010 Query on The Trees 点权LCT


题目:

http://acm.hdu.edu.cn/showproblem.php?pid=4010

题意:

给定一个有n个点的树,有以下四种操作:

  • 1 x y: 如果x y不在同一棵树上,那么在它们中间新建一条边,把他们连接起来,否则操作非法
  • 2 x y:如果x y在同一棵树上,那么把x替换为树根并且把y和y的父亲之间的边删掉,否则操作非法
  • 3 w x y:如果x y在同一棵树上,那么把xy路径上所有点的点权加上w,否则操作非法
  • 4 x y:如果x y在同一棵树上,查询x y路径上的最大点权,否则操作非法
  • 注意,非法操作都输出−1,无论是不是查询

思路:

直接LCT啊。。。我好像老把数据结构写搓,写搓了之后还不会debug,真是一场灾难,搞得我怀疑人生。。。

#include <bits/stdc++.h>

using namespace std;

const int N = 300000 + 10, INF = 0x3f3f3f3f;

struct edge
{
    int to, next;
}g[N*2];

int cnt, head[N];
int son[N][2], fat[N], key[N], maxval[N], rev[N], lazy[N];
int top, stk[N];

void init()
{
    cnt = 0;
    memset(head, -1, sizeof head);
    memset(son, 0, sizeof son);
    memset(key, 0, sizeof key);
    memset(fat, 0, sizeof fat);
    memset(rev, 0, sizeof rev);
    memset(lazy, 0, sizeof lazy);
    memset(maxval, 0, sizeof maxval);
}
void add_edge(int v, int u)
{
    g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;
}
void dfs(int v, int fa)
{
    fat[v] = fa;
    for(int i = head[v]; ~i; i = g[i].next)
    {
        int u = g[i].to;
        if(u == fa) continue;
        dfs(u, v);
    }
}
bool is_root(int x)
{
    return son[fat[x]][0] != x && son[fat[x]][1] != x;
}
void push_up(int x)
{
    maxval[x] = max(key[x], max(maxval[son[x][0]], maxval[son[x][1]]));
}
void push_down(int x)
{
    if(lazy[x])
    {//注意下放lazy标记时,如果不判断x的左右儿子是否存在而直接下放,相当于是下放到0这个点上,树上有很多点儿子为空都连接0,就会干扰到这些点,导致出现错误。。。
        if(son[x][0])
        {
            lazy[son[x][0]] += lazy[x];
            key[son[x][0]] += lazy[x];
            maxval[son[x][0]] += lazy[x];
        }
        if(son[x][1])
        {
            lazy[son[x][1]] += lazy[x];
            key[son[x][1]] += lazy[x];
            maxval[son[x][1]] += lazy[x];
        }
        lazy[x] = 0;
    }
    if(rev[x])
    {//翻转标记不用判断左右儿子是否存在
        swap(son[x][0], son[x][1]);
        rev[son[x][0]] ^= 1, rev[son[x][1]] ^= 1;
        rev[x] ^= 1;
    }
}
void Rotate(int x)
{
    int y = fat[x], p = son[y][0] == x;
    son[y][!p] = son[x][p], fat[son[x][p]] = y;
    if(! is_root(y)) son[fat[y]][son[fat[y]][1]==y] = x;
    fat[x] = fat[y];
    son[x][p] = y, fat[y] = x;
    push_up(y);
}
void splay(int x)
{
    top = 0;
    stk[++top] = x;
    for(int i = x; !is_root(i); i = fat[i]) stk[++top] = fat[i];
    for(int i = top; i >= 1; i--) push_down(stk[i]);
    while(! is_root(x))
    {
        int y = fat[x], z = fat[y];
        if(is_root(y)) Rotate(x);
        else
        {
            if((x == son[y][0]) ^ (y == son[z][0])) Rotate(x), Rotate(x);
            else Rotate(y), Rotate(x);
        }
    }
    push_up(x);
}
void access(int x)
{
    int y = 0;
    while(x)
    {
        splay(x);
        son[x][1] = y;
        push_up(x);
        y = x, x = fat[x];
    }
}
int find_root(int x)
{
    access(x); splay(x);
    while(son[x][0]) x = son[x][0];
    return x;
}
bool check(int x, int y)
{
    return find_root(x) == find_root(y);
}
void make_root(int x)
{
    access(x); splay(x);
    rev[x] ^= 1;
}
void link(int x, int y)
{
    if(check(x, y))
    {
        printf("-1\n"); return;
    }
    make_root(x); fat[x] = y;
}
void cut(int x, int y)
{
    if(x == y || !check(x, y))
    {
        printf("-1\n"); return;
    }
    make_root(x);
    access(y); splay(y);
    son[y][0] = fat[son[y][0]] = 0;
    push_up(y);
}
void update(int x, int y, int v)
{
    if(!check(x, y))
    {
        printf("-1\n"); return;
    }
    make_root(x);
    access(y); splay(y);
    lazy[y] += v, maxval[y] += v, key[y] += v;//此时y的右子树为空,所以可以这样更新
}
int query(int x, int y)
{
    if(!check(x, y)) return -1;
    make_root(x);
    access(y); splay(y);
    return maxval[y];
}
int main()
{
    int n, m, opt, x, y, z;
    while(~ scanf("%d", &n))
    {
        init();
        for(int i = 1; i <= n-1; i++)
        {
            scanf("%d%d", &x, &y);
            add_edge(x, y); add_edge(y, x);
        }
        for(int i = 1; i <= n; i++) scanf("%d", &key[i]), maxval[i] = key[i];
        dfs(1, 0);
        scanf("%d", &m);
        for(int i = 1; i <= m; i++)
        {
            scanf("%d%d%d", &opt, &x, &y);
            if(opt == 1) link(x, y);
            else if(opt == 2) cut(x, y);
            else if(opt == 3)
            {
                scanf("%d", &z);
                update(y, z, x);
            }
            else printf("%d\n", query(x, y));
        }
        printf("\n");
    }
    return 0;
}


举报

相关推荐

0 条评论