題目傳送門
題目大意:給出一顆樹,根節點是0,有兩種操作,一是修改某個節點的value,二是查詢,從根節點出發,經過 x 節點的路徑的最大值。
思路:用樹狀數組寫發現還是有些麻煩,最后用線段樹了。
其實這道題的查詢,就是查詢從根節點到x節點+x節點走下去的路徑的最大值,這樣會發現,其實就是查詢包括x節點的所有子樹中權值最大的那個,而包括x節點的子樹,如果用dfs序轉換一下的話,可以在線段上用一段連續的點表示出來,所以最后就轉換成了線段樹區間求最大值,然后單點修改的題目了。
要注意的是dfs序和原標號的對應,有一個地方弄反了,卡了好久。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<stdlib.h> #include<algorithm> #include<iostream> #include<cmath> #include<map> #define CLR(a,b) memset(a,b,sizeof(a)) #define PI acos(-1) #define lson rt*2,l,(l+r)/2 #define rson rt*2+1,(l+r)/2+1,r using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=100010; struct edge{int to,Next; }e[maxn*2]; int tot,m,n,head[maxn],pos,dfn[maxn],fa[maxn],son[maxn],l[maxn],r[maxn]; ll val[maxn],dis[maxn]; inline void init(){CLR(head,-1),tot=0,pos=0;CLR(dis,0);fa[1]=1; } inline void addv(int u,int v){e[++tot]={v,head[u]};head[u]=tot; } ll tree[maxn << 2], laz[maxn << 2]; inline void pushup(int rt) {tree[rt] = max(tree[rt << 1], tree[rt << 1 | 1]); } inline void pushdown(int rt) {if (laz[rt]) {tree[rt << 1] += laz[rt];tree[rt << 1 | 1] += laz[rt];laz[rt << 1] += laz[rt];laz[rt << 1 | 1] += laz[rt];laz[rt] = 0;} } inline void build(int rt, int l, int r) {laz[rt] = 0;if (l == r) {tree[rt] = dis[l];return ;}build(lson);build(rson);pushup(rt); } inline void update(int L, int R, ll v, int rt, int l, int r) {if (L <= l && R >= r) {tree[rt] += v;laz[rt] += v;return;}pushdown(rt);if (L <= (l + r) / 2) update(L, R, v, lson);if (R > (l + r) / 2) update(L, R, v, rson);pushup(rt); } inline ll query(int L, int R, int rt, int l, int r) { if (L <= l && R >= r) {return tree[rt];}pushdown(rt);if (L > (l + r) / 2) return query(L,R,rson);else if (R <= (l + r) / 2) return query(L,R,lson);else return max(query(L,R,lson),query(L,R,rson)); }inline void dfs(int u,int pre){dfn[u]=++pos;l[u]=pos;son[u]=1;dis[dfn[u]]=dis[dfn[pre]]+val[u];for(int i=head[u];i!=-1;i=e[i].Next){int v=e[i].to;if(v==fa[u])continue;fa[v]=u;dfs(v,u);son[u]+=son[v];}r[u]=pos; } int main(){int T,cas=1;cin>>T;while(T--){init();scanf("%d%d",&n,&m);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);addv(u+1,v+1);addv(v+1,u+1);}for(int i=1;i<=n;i++)scanf("%lld",&val[i]);dfs(1,1);build(1,1,n);printf("Case #%d:\n",cas++);while(m--){int op,x;ll y;scanf("%d%d",&op,&x);if(op==1){// printf("debug %d %d\n",dfn[x+1],dfn[x+1]+son[x+1]-1); printf("%lld\n",query(l[x+1],r[x+1],1,1,n));}else{scanf("%lld",&y);update(l[x+1],r[x+1],y-val[x+1],1,1,n);val[x+1]=y;}}} }
Snacks
Time Limit: 10000/5000 MS (Java/Others)????Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 5563????Accepted Submission(s): 1265
Problem Description
百度科技園內有n個零食機,零食機之間通過n?1條路相互連通。每個零食機都有一個值v,表示為小度熊提供零食的價值。
由于零食被頻繁的消耗和補充,零食機的價值v會時常發生變化。小度熊只能從編號為0的零食機出發,并且每個零食機至多經過一次。另外,小度熊會對某個零食機的零食有所偏愛,要求路線上必須有那個零食機。
為小度熊規劃一個路線,使得路線上的價值總和最大。
由于零食被頻繁的消耗和補充,零食機的價值v會時常發生變化。小度熊只能從編號為0的零食機出發,并且每個零食機至多經過一次。另外,小度熊會對某個零食機的零食有所偏愛,要求路線上必須有那個零食機。
為小度熊規劃一個路線,使得路線上的價值總和最大。
?
Input
輸入數據第一行是一個整數T(T≤10),表示有T組測試數據。
對于每組數據,包含兩個整數n,m(1≤n,m≤100000),表示有n個零食機,m次操作。
接下來n?1行,每行兩個整數x和y(0≤x,y<n),表示編號為x的零食機與編號為y的零食機相連。
接下來一行由n個數組成,表示從編號為0到編號為n?1的零食機的初始價值v(|v|<100000)。
接下來m行,有兩種操作:0?x?y,表示編號為x的零食機的價值變為y;1?x,表示詢問從編號為0的零食機出發,必須經過編號為x零食機的路線中,價值總和的最大值。
本題可能棧溢出,辛苦同學們提交語言選擇c++,并在代碼的第一行加上:
`#pragma comment(linker, "/STACK:1024000000,1024000000") `
對于每組數據,包含兩個整數n,m(1≤n,m≤100000),表示有n個零食機,m次操作。
接下來n?1行,每行兩個整數x和y(0≤x,y<n),表示編號為x的零食機與編號為y的零食機相連。
接下來一行由n個數組成,表示從編號為0到編號為n?1的零食機的初始價值v(|v|<100000)。
接下來m行,有兩種操作:0?x?y,表示編號為x的零食機的價值變為y;1?x,表示詢問從編號為0的零食機出發,必須經過編號為x零食機的路線中,價值總和的最大值。
本題可能棧溢出,辛苦同學們提交語言選擇c++,并在代碼的第一行加上:
`#pragma comment(linker, "/STACK:1024000000,1024000000") `
?
Output
對于每組數據,首先輸出一行”Case #?:”,在問號處應填入當前數據的組數,組數從1開始計算。
對于每次詢問,輸出從編號為0的零食機出發,必須經過編號為x零食機的路線中,價值總和的最大值。
對于每次詢問,輸出從編號為0的零食機出發,必須經過編號為x零食機的路線中,價值總和的最大值。
?
Sample Input
1 6 5 0 1 1 2 0 3 3 4 5 3 7 -5 100 20 -5 -7 1 1 1 3 0 2 -1 1 1 1 5
?
Sample Output
Case #1: 102 27 2 20