hdu 6161 Big binary tree(脑洞)
题意:
给你n个点,和m条操作,一开始n个点构成一个完全二叉树,每个点的权值为该点编号。
每个操作可能为
1.询问经过x点的最大路径(该路径上的点权之和最大)。
2.修改x点的权值。
题解:
下面是官方题解
考虑dp,f(x)表示从点x开始向下走得到的最大的点权和,查询直接从x开始向上走更新答案即可。
考虑快速算 f(x) 对于子树内没有被修改过的点的 f(x) 可以快速分类讨论算出,而不满足本条件的点只有 O(mlogm) 个,在hash上dp即可。
我的做法类似,然后多开了个g(x)表示x点的值,每次计算的时候是递归计算的,没有dp。我算f(x)的时候是一直往右儿子走,但是由于这是一棵完全二叉树,不一定会满,所以有一个节点的f(x)会错,那个is(x)就是记录的那条错误的链上的点的信息。
1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);++i) 4 using namespace std; 5 typedef long long ll; 6 7 map<int,ll>mp,mmp,is; 8 int n,m; 9 10 ll f(int x) 11 { 12 if(x>n)return 0; 13 if(mp.find(x)!=mp.end())return mp[x]; 14 if(is.find(x)!=is.end())return is[x]; 15 ll ans=0; 16 while(x<=n)ans+=x,x=x*2+1; 17 return ans; 18 } 19 20 ll g(int x) 21 { 22 if(x>n)return 0; 23 if(mmp.find(x)!=mmp.end())return mmp[x]; 24 return x; 25 } 26 27 void chang(int a,ll b) 28 { 29 mp[a]=b+max(f(a*2),f(a*2+1)); 30 mmp[a]=b; 31 for(a/=2;a>=1;a/=2) 32 { 33 mp[a]=g(a)+max(f(a*2),f(a*2+1)); 34 } 35 } 36 37 void dfs(int x,ll sum,ll &ans) 38 { 39 if(x==1)return; 40 int fx=x/2; 41 ans=max(ans,sum+g(fx)+f(x^1)); 42 dfs(fx,sum+g(fx),ans); 43 } 44 45 ll query(int x) 46 { 47 ll ans=f(x*2)+f(x*2+1)+g(x); 48 dfs(x,f(x),ans); 49 return ans; 50 } 51 52 int main(){ 53 while(~scanf("%d%d",&n,&m)) 54 { 55 mp.clear(),mmp.clear(),is.clear(); 56 ll now=0;int x=n; 57 while(x>=1)now+=x,is[x]=now,x/=2; 58 F(i,1,m) 59 { 60 char op[10];int a;ll b; 61 scanf("%s",op); 62 if(*op=='q') 63 { 64 scanf("%d",&a); 65 printf("%lld\n",query(a)); 66 }else scanf("%d%lld",&a,&b),chang(a,b); 67 } 68 } 69 return 0; 70 }