HDU 5692 线段树

点击打开链接

题意:中文题目

思路:这还是第一次写这样的线段树,个人感觉是一种套路之前没做过,但是思想什么巧妙,将一颗树转化成线段树真厉害,先是将每个节点的下面的所有数进行dfs编序号,并将他们的左右编号记下来,也就是我的代码中的L和R,而val记录的是根节点0到当前位置的费用,建树之后就很好操作了,更新时便找到当前节点的儿子和自己代表的区间,然后区间更新,注意题目说更新一个节点的值变为y,我们为什么更新一段,因为我们线段树的节点保存的是到根节点0的费用,那么作为一个父亲节点,它的值变了,自然会影响它的所有儿子到根节点的费用,而且变化的相同,所以用区间更新来完成,查询也是一样,必须到x节点,那么到了x节点后是不是还会有更大的费用呢,而这个费用的点肯定要经过x节点,所以我们直接查询x节点和它的所有儿子的最大值即可
   PS:树形的结构与线段树完美结合,要好好练练才行

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int maxn=100010;
vector<int>G[maxn];
ll max1[maxn*4],lazy[maxn*4],val[maxn];
int L[maxn],R[maxn],cost[maxn];
int idx;
void dfs(int u,int f,ll vv){
    L[u]=++idx;
    for(unsigned int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v==f) continue;
        dfs(v,u,(ll)cost[v]+vv);
    }
    R[u]=idx;
    val[L[u]]=vv;
}
void pushup(int node){
    max1[node]=max(max1[node<<1],max1[node<<1|1]);
}
void pushdown(int node){
    if(lazy[node]){
        lazy[node<<1]+=lazy[node];
        lazy[node<<1|1]+=lazy[node];
        max1[node<<1]+=lazy[node];
        max1[node<<1|1]+=lazy[node];
        lazy[node]=0;
    }
}
void buildtree(int le,int ri,int node){
    if(le==ri){
        max1[node]=val[le];
        return ;
    }
    int t=(le+ri)>>1;
    buildtree(le,t,node<<1);
    buildtree(t+1,ri,node<<1|1);
    pushup(node);
}
void update(int l,int r,int x,int le,int ri,int node){
    if(l<=le&&ri<=r){
        lazy[node]+=(ll)x;
        max1[node]+=(ll)x;
        return ;
    }
    pushdown(node);
    int t=(le+ri)>>1;
    if(l<=t) update(l,r,x,le,t,node<<1);
    if(r>t) update(l,r,x,t+1,ri,node<<1|1);
    pushup(node);
}
ll query(int l,int r,int le,int ri,int node){
    if(l<=le&&ri<=r) return max1[node];
    pushdown(node);
    ll ans=-inf;
    int t=(le+ri)>>1;
    if(l<=t) ans=max(ans,query(l,r,le,t,node<<1));
    if(r>t) ans=max(ans,query(l,r,t+1,ri,node<<1|1));
    return ans;
}
int main(){
    int T,cas=1,n,m,a,b,c;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<maxn;i++) G[i].clear();
        for(int i=0;i<n-1;i++){
            scanf("%d%d",&a,&b);
            a++;b++;
            G[a].push_back(b);
            G[b].push_back(a);
        }
        for(int i=1;i<=n;i++) scanf("%d",&cost[i]);
        idx=0;dfs(1,0,(ll)cost[1]);
        buildtree(1,n,1);
        memset(lazy,0,sizeof(lazy));
        printf("Case #%d:\n",cas++);
        while(m--){
            scanf("%d",&a);
            if(a==0){
                scanf("%d%d",&b,&c);b++;
                update(L[b],R[b],c-cost[b],1,n,1);
                cost[b]=c;
            }else{
                scanf("%d",&b);b++;
                ll answe=query(L[b],R[b],1,n,1);
                printf("%I64d\n",answe);
            }
        }
    }
    return 0;
}
时间: 2024-11-05 16:26:24

HDU 5692 线段树的相关文章

HDU 5692 线段树+dfs序

Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1779    Accepted Submission(s): 427 Problem Description 百度科技园内有n 个零食机,零食机之间通过n−1 条路相互连通.每个零食机都有一个值v ,表示为小度熊提供零食的价值. 由于零食被频繁的消耗和补充,零食机的价值v

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对 参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍 #include <cstdio> #include <cstring> #include <a

HDU 4902 线段树||暴力

给定一个序列,两种操作 1:把一段变成x. 2:把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 线段树解法:用lazy标记下即可,优化方法还是很巧妙的, Accepted 4902 515MS 3308K 1941 B C++ #include "stdio.h" #include "string.h" struct node { int l,r,x;// 在叶子节点代表值,树节点代表成端更新的lazy操作. }data[400010]

HDU 4302 线段树单点更新,维护区间最大最小值

http://acm.hdu.edu.cn/showproblem.php?pid=4302 Problem Description Holedox is a small animal which can be considered as one point. It lives in a straight pipe whose length is L. Holedox can only move along the pipe. Cakes may appear anywhere in the p

HDU 3397 线段树 双懒惰标记

这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了 自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了 跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全部置为0或者1,没有置位的时候为-1 还有个rev标记,代表翻转操作,0代表当前不翻,1代表当前翻 要注意一下优先级,发现有不同的弄法,我是这个弄得,有set操作的时候,set标记设值,并把当前节点的rev标记设为0,因为不管要不要rev,当前set操作肯定直接覆盖了 rev操作不改变set操作,在

hdu 2795 线段树--点更新

http://acm.hdu.edu.cn/showproblem.php?pid=2795 多校的第一场和第三场都出现了线段树,比赛期间没做,,这两天先做几道热身下,然后31号之前把那两道多校的线段树都搞了,这是一道热身题 关键是建模: 首先一定看清楚题目构造的场景,看有什么特点--------会发现,如果尽量往左上放置的话,那么由于 the i-th announcement is a rectangle of size 1 * wi.,完全可以对h建立线段树,表示一行,结点里的l,r就表示

HDU 1698 线段树(区间染色)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16255    Accepted Submission(s): 8089 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing f