HDOJ5692解题报告dfs序+线段树
Posted CtrlKismet
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDOJ5692解题报告dfs序+线段树相关的知识,希望对你有一定的参考价值。
题目地址:
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 #define Eps 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序+线段树的主要内容,如果未能解决你的问题,请参考以下文章