HDU-5692-Snacks(DFS序+線段樹,單點修改,區間查詢)
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5692
Problem Description 百度科技園內有n 個零食機,零食機之間通過n−1 條路相互連通。每個零食機都有一個值v ,表示為小度熊提供零食的價值。
Input 輸入資料第一行是一個整數T(T≤10) ,表示有T 組測試資料。
Output 對於每組資料,首先輸出一行”Case #?:”,在問號處應填入當前資料的組數,組數從1開始計算。
Sample Input Sample Output |
中文題,題意很好懂,題目可以理解成:對於一棵樹,修改一個點,或,查詢那顆點一下的子樹的的最大值,很容易想到線段樹解決,學了一下DFS序,發現這道題是 問題1的變形,只不過換成取最大值,理解DFS序後就比較簡單了;
注意,我這裡沒法用memset,因為用之後就直接70K+的記憶體空間,直接MLE,但改成手動賦值之後就只有13K+的記憶體空間,我也不太清楚,還有就是輸入輸出scanf,負責會TLE。。
ac:
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<math.h> #include<stdlib.h> //#include<map> //#include<set> #include<deque> #include<queue> #include<stack> #include<bitset> #include<string> #include<fstream> #include<iostream> #include<algorithm> using namespace std; #define ll long long //#define max(a,b) (a)>(b)?(a):(b) //#define min(a,b) (a)<(b)?(a):(b) #define clean(a,b) memset(a,b,sizeof(a))// 水印 //std::ios::sync_with_stdio(false); const int MAXN=1e5+5; const ll INF=1e18; const ll mod=1e9+7; struct node{ int v,w,nxt; node(int _v=0,int _nxt=0): v(_v),nxt(_nxt){} }edge[MAXN<<1]; int head[MAXN],ecnt; ll tree[MAXN<<2],add[MAXN<<2],value[MAXN],dis[MAXN]; int L[MAXN],R[MAXN],arr[MAXN]; //x所對應線上段樹左的節點,同理右,線段樹上x對應的節點是多少arr[x]; int n,m,cnt; void intt() { // clean(L,0); // clean(R,0); // clean(dis,0); // clean(add,0); // clean(tree,0); // clean(value,0); clean(head,-1); // memset(head,-1,sizeof(head)); ecnt=0; cnt=0;//從0開始變成從1開始 } void add_edge(int u,int v) { edge[ecnt]=node(v,head[u]); head[u]=ecnt++; } void dfs(int u,int fa) { L[u]=++cnt; arr[cnt]=u; for(int i=head[u];i+1;i=edge[i].nxt) { int v=edge[i].v; if(v==fa) continue; dis[v]=dis[u]+value[v]; dfs(v,u); } R[u]=cnt; } void push_down(int rt) { if(add[rt]) { tree[rt<<1]+=add[rt]; tree[rt<<1|1]+=add[rt]; add[rt<<1]+=add[rt]; add[rt<<1|1]+=add[rt]; add[rt]=0; } } void build_tree(int l,int r,int rt) { add[rt]=0; if(l==r) { tree[rt]=dis[arr[l]]; return ; } int mid=(l+r)>>1; build_tree(l,mid,rt<<1); build_tree(mid+1,r,rt<<1|1); tree[rt]=max(tree[rt<<1],tree[rt<<1|1]); } void updata(int left,int right,int val,int l,int r,int rt) { if(left<=l&&right>=r)//找到目標範圍 { add[rt]+=val; tree[rt]+=val; return ; } //有一部分在範圍外 push_down(rt);//向下推進 int mid=(l+r)>>1; if(left<=mid) updata(left,right,val,l,mid,rt<<1); if(right>mid) updata(left,right,val,mid+1,r,rt<<1|1); tree[rt]=max(tree[rt<<1],tree[rt<<1|1]); } ll Query(int left,int right,int l,int r,int rt) { if(left<=l&&right>=r) return tree[rt]; push_down(rt); int mid=(l+r)>>1; ll ans=-INF; if(left<=mid) ans=max(ans,Query(left,right,l,mid,rt<<1)); if(right>mid) ans=max(ans,Query(left,right,mid+1,r,rt<<1|1)); return ans; } int main() { //std::ios::sync_with_stdio(false); int T,Case=1; scanf("%d",&T); while(T--) { //cout<<"T: "<<T<<endl; intt(); scanf("%d%d",&n,&m); int a,b; for(int i=1;i<n;++i)//建邊 { scanf("%d%d",&a,&b); add_edge(a,b); add_edge(b,a); } for(int i=0;i<n;++i)//讀入權值 scanf("%lld",&value[i]);//cin>>value[i]; dis[0]=value[0]; dfs(0,-1); build_tree(1,n,1); bool oper; cout<<"Case #"<<Case++<<":"<<endl; for(int i=1;i<=m;++i) { scanf("%d",&oper); if(oper)//找 { scanf("%d",&a); cout<<Query(L[a],R[a],1,n,1)<<endl; } else//換 { scanf("%d%d",&a,&b); updata(L[a],R[a],b-value[a],1,n,1); value[a]=b; } } } } /* 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 */