Tyvj4071放射性辐射尘题解

本文介绍了一种使用链剖分树(LCT)解决特定树形结构数据问题的方法,包括单点权值更新及路径最大权值查询。通过具体实现代码展示了如何进行节点旋转、路径访问等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源

http://www.tyvj.cn/p/4071

题目大意
  • 给定一棵树,支持修改单点的权值和查询某一路径上权值最大的点,总点数不超过100000。
题解
  • 反正是要退役了,LCT这种东西NOIP是用不到了,就拿这个题和这种优美的数据结构说再见吧。
  • LCT维护每条实链上权值最大的点。单点修改时先access,再splay,然后直接改,再维护一下实链上权值最大的点的下标就可以了。查询时先把第一个点置为根,再access并splay第二个点,然后第二个点所在实链上点权最大的那个点即为答案。
  • 这是很基础的LCT操作了,连化边为点都没用上。
Code
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 100005
#define nil 0
using namespace std;
int n, root, q;
bool rev[N];
int val[N], mx[N], fa[N], lc[N], rc[N];
int S[N];
inline void update(int x)
{
    mx[x] = x;
    if(lc[x] != nil) if(val[mx[lc[x]]] > val[mx[x]]) mx[x] = mx[lc[x]];
    if(rc[x] != nil) if(val[mx[rc[x]]] > val[mx[x]]) mx[x] = mx[rc[x]];
}
inline void pushdown(int x)
{
    if(rev[x])
    {
        swap(lc[x], rc[x]);
        rev[lc[x]] ^= 1; rev[rc[x]] ^= 1;
        rev[x] = false;
    }
}
void zig(int x)
{
    int y = fa[x];
    lc[y] = rc[x];
    fa[rc[x]] = y;
    rc[x] = y;
    fa[x] = fa[y];
    if(y == lc[fa[y]]) lc[fa[y]] = x;
    else if(y == rc[fa[y]]) rc[fa[y]] = x;
    fa[y] = x;
    update(y);
}
void zag(int x)
{
    int y = fa[x];
    rc[y] = lc[x];
    fa[lc[x]] = y;
    lc[x] = y;
    fa[x] = fa[y];
    if(y == lc[fa[y]]) lc[fa[y]] = x;
    else if(y == rc[fa[y]]) rc[fa[y]] = x;
    fa[y] = x;
    update(y);
}
void splay(int x)
{
    int top = 0;
    S[top++] = x;
    for(int i = x; i == lc[fa[i]] || i == rc[fa[i]]; i = fa[i])
    {
        S[top++] = fa[i];
    }
    while(top--) pushdown(S[top]);
    int y = nil, z = nil;
    while(x == lc[fa[x]] || x == rc[fa[x]])
    {
        y = fa[x]; z = fa[y];
        if(x == lc[y])
        {
            if(y == lc[z]) zig(y);
            zig(x);
        }
        else
        {
            if(y == rc[z]) zag(y);
            zag(x);
        }
    }
    update(x);
}
inline int access(int x)
{
    int y = nil;
    for(y = nil; x != nil; y = x, x = fa[x])
    {
        splay(x);
        rc[x] = y;
        update(x);
    }
    return y;
}
inline int getLCA(int x, int y)
{
    access(x);
    return access(y);
}
inline void makeroot(int x)
{
    access(x); splay(x);
    rev[x] ^= 1;
}
inline void lnk(int x, int y)
{
    makeroot(x);
    fa[x] = y;
}
inline void cut(int x, int y)
{
    makeroot(x);
    access(y); splay(y);
    fa[x] = lc[y] = nil;
    update(y);
}
inline int query(int x, int y)
{
    makeroot(x);
    access(y); splay(y);
    return mx[y];
}
void init()
{
    scanf("%d", &n);
    int a, b;
    for(int i = 1; i <= n; ++i) mx[i] = i;
    for(int i = 1; i < n; ++i)
    {
        scanf("%d%d", &a, &b);
        lnk(a, b);
    }
    scanf("%d", &q);
}
void work()
{
    char opt[5];
    int a, b, ansl, ansf, lca;
    scanf("%d", &q);
    while(q--)
    {
        scanf("%s", opt);
        switch(opt[0])
        {
            case 'I': scanf("%d%d", &a, &b);
                      access(a); splay(a);
                      val[a] += b;
                      update(a);
                      break;
            case 'G': scanf("%d%d", &a, &b);
                      printf("%d\n", val[query(a, b)]);
            default : break;
        }
    }
}        
int main()
{
    init();
    work();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值