P4315 月下“毛景树” 边权改点权问题

洛谷P4315

//Change k w:将第k条树枝上毛毛果的个数改变为w个。
//Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。
//Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问:
//Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。
//这题的重点在两个标记的同步问题和边权变点权问题,当改变权值时,要把节点的加的lazy置为0,增加 加的操作时lazy直接加
//pushdown的时候先操作置换的标记再操作加法的标记
//然后是边权改点权,因为只有N- 1条边,所以就把边的权值给两端深度更低的节点
//再query的时候,其他代码不变,只是当询问的两个点在同一条重链上的时候要将深度低的节点加一,***
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 50;
int fa[maxn], dep[maxn], size[maxn], son[maxn], top[maxn], dfn[maxn], rid[maxn], cnt = 0;
ll val[maxn];
vector<int> g[maxn];
struct node {
    int l, r;
    ll lazy, val, tag;
}t[maxn * 4];
//第一遍求fa,dep,siz,son数组
void dfs1(int u, int f)//fa是父亲节点,dep是该节点的深度,size是以该节点为根的大小,son是重儿子
{
    fa[u] = f;
    dep[u] = dep[f] + 1;
    size[u] = 1;
    for (int i = 0; i < g[u].size(); i++)
    {
        int v = g[u][i];
        if(v != f) {
            dfs1(v, u);
            size[u] += size[v];
            if(size[v] > size[son[u]]) son[u] = v;
        }
    }
}
//第二遍找出重链,求出top数组
void dfs2(int now, int fir)//cnt计数器,dfn是dfs序,top是该节点所在重链的头,rid是按dfs序的节点编号
{
    cnt++;
    top[now] = fir;
    dfn[now] = cnt;//第now个节点的编号是cnt
    rid[dfn[now]] = now;//第cnt个编号的节点是now
    if(!son[now]) return;//如果没有重儿子,说明已经到了叶子节点
    dfs2(son[now], fir);//走重儿子所在的链
    for (int i = 0; i < g[now].size(); i++)//然后走轻儿子的边
    {
        int v = g[now][i];
        if(v != fa[now] && v != son[now])
            dfs2(v, v);//以轻儿子开始再找重链
    }
}
void pushup(int n)
{
    t[n].val = max(t[n<<1].val, t[n<<1|1].val);
}
void pushdown(int n)
{
    int l = t[n].l, r = t[n].r;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(t[n].tag != -1) {
        t[n<<1].tag = t[n<<1|1].tag = t[n].tag;
        t[n<<1].val = t[n<<1|1].val = t[n].tag;
        t[n<<1].lazy = t[n<<1|1].lazy = 0;
        t[n].tag = -1;
    }
    if(t[n].lazy)
    {
        t[n<<1].lazy += t[n].lazy;
        t[n<<1|1].lazy += t[n].lazy;
        t[n<<1].val += t[n].lazy;
        t[n<<1|1].val += t[n].lazy;
        t[n].lazy = 0;
    }
}
void build(int n, int l, int r)
{
    t[n].l = l;
    t[n].r = r;
    t[n].lazy = 0;
    t[n].tag = -1;
    if(l == r) {
        t[n].val = val[rid[l]];
        return;
    }
    int mid = (l + r) >> 1;
    build(n<<1, l, mid);
    build(n<<1|1, mid + 1, r);
    pushup(n);
}
void update(int n, int L, int R, ll val, int op)
{
    int l = t[n].l, r = t[n].r;
    if(L <= l && R >= r) {
        if(op == 1) {//+
            t[n].lazy += val;
            t[n].val += val;
        }
        else {//change
            t[n].val = val;
            t[n].tag = val;
            t[n].lazy = 0;
        }
        return;
    }
    pushdown(n);
    int mid = (l + r)>>1;
    if(L <= mid) update(n<<1, L, R, val, op);
    if(R > mid) update(n<<1|1, L, R, val, op);
    pushup(n);
}
ll query(int n, int L, int R)
{
    int l = t[n].l, r = t[n].r;
    if(L <= l && R >= r) return t[n].val;
    pushdown(n);
    int mid = (l + r) >>1;
    ll ans = 0;
    if(L <= mid) ans = max(ans, query(n<<1, L, R));
    if(R > mid) ans = max(ans, query(n<<1|1, L, R));
    pushup(n);
    return ans;
}
void subtreechange(int x, int val, int op)//修改x的所有子树的权值
{
    update(1, dfn[x], dfn[x] + size[x] - 1, val, op);
}
ll subtreequery(int x)//询问x的所有子树的权值和
{
    return query(1, dfn[x], dfn[x] + size[x] - 1);
}
void linkchange(int x, int y, int z, int op)//修改x和以X为根的子树的所有节点的权值
{
    while (top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]])
            swap(x, y);
        update(1, dfn[top[x]], dfn[x], z, op);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);			//重要是加一操作,因为两个节点之间有差值减一条边
						//深度低的节点代表的边权不在要求的范围内
    if(dfn[x] + 1 <= dfn[y]) update(1, dfn[x] + 1, dfn[y], z, op);//这个判断操作好像没有必要,因为按照这个程序进行,条件一定
						//满足,WA的时候再加上吧
}
ll linkquery(int x, int y)//询问从x到y节点的路上的节点权值的和
{
    ll ret = 0;
    while (top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        ret = max(ret, query(1, dfn[top[x]], dfn[x]));
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    if(dfn[x] + 1 <= dfn[y]) ret = max(ret, query(1, dfn[x] + 1, dfn[y]));
    return ret;
}
struct linex {
    int x, y, z;
}line[maxn];
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n - 1; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        g[u].push_back(v);
        g[v].push_back(u);
        line[i].x = u; line[i].y = v; line[i].z = w;
    }
    dfs1(1, 1);
    for (int i = 1; i <= n - 1; i++)
        val[fa[line[i].x] == line[i].y ? line[i].x : line[i].y] = line[i].z;
//    for (int i = 1; i <= n; i++) {
//        printf("%lld ", val[i]);
//    }
//    printf("\n");
    dfs2(1, 0);
    build(1, 1, n);
    char s[20];
    while (1)
    {
        scanf("%s", s);
        int u, v, w;
        if(s[1] == 't') break;
        if(s[1] == 'a') {
            scanf("%d%d",&u, &v);
            printf("%lld\n", linkquery(u, v));
        }
        if(s[1] == 'o') {
            scanf("%d%d%d", &u, &v, &w);
            linkchange(u, v, w, 2);
        }
        if(s[1] == 'd') {
            scanf("%d%d%d", &u, &v, &w);
            linkchange(u, v, w, 1);
        }
        if(s[1] == 'h') {
            scanf("%d%d", &u, &w);
            int z = fa[line[u].x] == line[u].y ? line[u].x : line[u].y;
            update(1, dfn[z], dfn[z], w, 2);//单点更新记得是更新dfs序的节点,而不是直接更新z节点
        }
    }
    return 0;
}
发布了26 篇原创文章 · 获赞 2 · 访问量 424

猜你喜欢

转载自blog.csdn.net/D_Bamboo_/article/details/103355562
今日推荐