2017多校第9场 HDU 6161 Big binary tree 思维,类似字典树
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6161
题意:
题目是给一棵完全二叉树,从上到下从左到右给每个节点标号,每个点有权值,初始权值为其标号,然后有两种操作:
1、把u点权值改为x
2、查询所有经过u点的路径中,路径上的点权和最大。
节点有n个,修改有m个,n<=1e8 ,m<= 1e5
解法:现场队友过的,orz,来自队友的思路。
我们首先对于一个点,如果没有访问我们不把它建出来,相反访问了就把它建出来,这个题的最小的子问题就是计算一个节点的答案怎么算,我们直接往右子树怼?显然并不全是,我们发现从n上来这一条链上的节点的答案并不一定是一直往右走,所以我们特殊处理这条链就可以 了。这就解决了最小的子问题,用log2n的复杂度算出了每个节点的答案,接下来就是更新和查询,更新的话,我们先更新这个节点,然后从这个节点到1这条链上的点都要更新,我们直接更新上去即可,对于查询来说,和更新一样我们只需要关心这个点所在的链上的信息,所以我们直接往上跑并且查询,这里查询就要贪心一下,如果有左儿子就累加上靠右儿子的答案,否则累加左儿子的答案,这里画个图模拟一下即可,这些点的信息可以用unorder_map和unorder_set来方便的维护,复杂度O(logn*logn)。
#include <bits/stdc++.h> using namespace std; typedef long long LL; unordered_map<int,pair<LL,LL> >mp;//u点,左儿子,右儿子 unordered_map<int,LL>now;//现在这个u节点的值 unordered_set<int>st;//题解上说的那条特殊链 int n,m; LL cal(int u){ if(u>n) return 0; if(mp.count(u)){ auto p=mp[u]; return max(p.first,p.second); } if(st.count(u)){ int v1=u*2; int v2=u*2+1; if(st.count(v1)) return u+cal(v1); else return u+cal(v2); } return u+cal(u*2+1); } void init(){ mp.clear(); st.clear(); int t=n; do{ st.insert(t); t/=2; }while(t); } void update(int u, LL val){ if(mp.count(u)==0){ mp.emplace(u, make_pair(cal(u*2)+u,cal(u*2+1)+u)); now[u]=u; } auto &p=mp[u]; p.first+=val-now[u]; p.second+=val-now[u]; now[u]=val; int t=u; u/=2; while(u){ if(mp.count(u)==0){ mp.emplace(u, make_pair(cal(u*2)+u,cal(u*2+1)+u)); now[u]=u; } else{ auto &p2=mp[u]; if(u*2==t){ p2.first=now[u]+cal(u*2); } else{ p2.second=now[u]+cal(u*2+1); } } u/=2; t/=2; } } LL query(int u){ LL ans=0; if(mp.count(u)==0){ mp.emplace(u,make_pair(u+cal(u*2),u+cal(u*2+1))); now[u]=u; } auto &p=mp[u]; ans = p.first+p.second-now[u]; LL len = max(p.first, p.second); int t=u; u/=2; while(u){ if(mp.count(u)==0){ mp.emplace(u,make_pair(cal(u*2)+u,cal(u*2+1)+u)); now[u]=u; } auto &p=mp[u]; if(u*2==t){ ans=max(ans,p.second+len); } else{ ans=max(ans,p.first+len); } len+=now[u]; t/=2; u/=2; } return ans; } int main() { while(~scanf("%d%d", &n,&m)) { init(); for(int i=1; i<=m; i++){ char op[10]; scanf("%s", op); if(op[0] == 'q'){ int x; scanf("%d", &x); printf("%lld\n", query(x)); } else{ int x; LL y; scanf("%d%lld", &x,&y); update(x,y); } } } return 0; }