HDOJ5692解題報告【dfs序+線段樹】
阿新 • • 發佈:2017-07-15
註意 表示 pre fine efi tree using push cnblogs
題目地址:
http://acm.hdu.edu.cn/showproblem.php?pid=5692
題目概述:
中文題面就不贅述了。
大致思路:
這個題給出的是一棵樹,我們可以使用dfs序將這棵樹處理成一條鏈,然後對這條鏈來進行信息維護和查詢。
有兩種操作,0 x是詢問從0出發(題目保證0為樹根)經過x的路徑中的最大權值,1 x y是將點x的權值修改成y,這時我們用線段樹來維護一個d[i]表示點i到0點的權值和。
對於第一種操作就是查詢x及其子樹上的最大值,經過dfs序的處理之後這是一段連續的區間,求一個最大值即可。
對於第二種操作我們只需要在x及其子樹上add一個y-a[x]即可。
註意可能爆棧,記得按題目裏的提示處理。
復雜度分析:
dfs序是O(n),線段樹查詢跟區間修改是O(logn),建樹O(nlogn),綜上O(nlogn*T)
代碼:
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <vector> #include <ctime> #include <map> #include<assert.h> #include <stack> #include <set> #include <queue> #include <cstring> #include <algorithm> using namespace std; #define sacnf scanf #define scnaf scanf #define maxn 100010 #define maxm 18 //#define inf 1061109567 const long long inf=1e15; #define INF 0x3f3f3f3f #defineEps 0.000001 const double PI=acos(-1.0); #define mod 1000000007 #define MAXNUM 10000 #define For(i,j,k) for(int (i)=(j);(i)<=(k);(i)++) #define mes(a,b) memset((a),(b),sizeof(a)) #define scanfi(a) scanf("%d",&(a)) typedef long long ll; typedef unsigned long long ulld; void Swap(int &a,int &b) {int t=a;a=b;b=t;} ll Abs(ll x) {return (x<0)?-x:x;} struct node { ll Add,Max; } tree[maxn*3]; vector<int> G[maxn]; int dfs_clock,pre[maxn],low[maxn],turn[maxn]; ll d[maxn],a[maxn]; void dfs(int u,ll sum) { if(pre[u]) return; pre[u]=++dfs_clock; int len=G[u].size(); For(i,0,len-1) { int v=G[u][i]; dfs(v,sum+a[u]); } low[u]=dfs_clock;d[pre[u]]=sum+a[u]; turn[u]=pre[u]; } void build_tree(int l,int r,int dir) { if(l==r) { tree[dir].Add=0; tree[dir].Max=d[l]; return; } int m=(l+r)>>1; build_tree(l,m,dir*2); build_tree(m+1,r,dir*2+1); tree[dir].Add=0; tree[dir].Max=max(tree[dir*2].Max,tree[dir*2+1].Max); } void add_in(int dir,ll val) { tree[dir].Add+=val; tree[dir].Max+=val; } void push_down(int dir) { if(tree[dir].Add!=0) { add_in(dir*2,tree[dir].Add); add_in(dir*2+1,tree[dir].Add); tree[dir].Add=0; } } void maintain(int dir) { tree[dir].Max=max(tree[dir*2].Max,tree[dir*2+1].Max); } void add(int l,int r,int dir,int al,int ar,ll val) { if(al<=l&&r<=ar) {add_in(dir,val);return;} push_down(dir); int m=(l+r)>>1; if(al<=m) add(l,m,dir*2,al,ar,val); if(ar>m) add(m+1,r,dir*2+1,al,ar,val); maintain(dir); } ll ans; void query(int l,int r,int dir,int ql,int qr) { if(ql<=l&&r<=qr) {ans=max(ans,tree[dir].Max);return;} push_down(dir); int m=(l+r)>>1; if(ql<=m) query(l,m,dir*2,ql,qr); if(qr>m) query(m+1,r,dir*2+1,ql,qr); maintain(dir); } int main() { //freopen("data.in","r",stdin); //freopen("data.out","w",stdout); //clock_t st=clock(); int T;scanfi(T); For(kase,1,T) { printf("Case #%d:\n",kase); int n,m;scanf("%d%d",&n,&m); For(i,1,n) { G[i].clear();d[i]=turn[i]=0; pre[i]=low[i]=dfs_clock=0; } For(i,1,n-1) { int x,y;scanf("%d%d",&x,&y); x++;y++;G[x].push_back(y); G[y].push_back(x); } For(i,1,n) scanf("%lld",&a[i]); dfs(1,0);build_tree(1,n,1); //cout<<endl;For(i,1,n) printf("%d\n",d[i]);cout<<endl; int opt,x;ll y; while(m--) { scanfi(opt); if(opt==0) { scanf("%d%lld",&x,&y);x++; add(1,n,1,pre[x],low[x],y-a[x]);a[x]=y; } else if(opt==1) { scanfi(x);x++;ans=-inf; query(1,n,1,pre[x],low[x]); printf("%lld\n",ans); } } } //clock_t ed=clock(); //printf("\n\nTime Used : %.5lf Ms.\n",(double)(ed-st)/CLOCKS_PER_SEC); return 0; }
HDOJ5692解題報告【dfs序+線段樹】