(补题)A - Big binary tree(map储存二叉树,完全二叉树,树型dp)
A - Big binary tree
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 849 Accepted Submission(s): 323
Problem Description
You are given a complete binary tree with n nodes. The root node is numbered 1, and node x's father node is ⌊x/2⌋. At the beginning, node x has a value of exactly x. We define the value of a path as the sum of all nodes it passes(including two ends, or one if the path only has one node). Now there are two kinds of operations:
1. change u x Set node u's value as x(1≤u≤n;1≤x≤10^10)
2. query u Query the max value of all paths which passes node u.
Input
There are multiple cases.
For each case:
The first line contains two integers n,m(1≤n≤10^8,1≤m≤10^5), which represent the size of the tree and the number of operations, respectively.
Then m lines follows. Each line is an operation with syntax described above.
Output
For each query operation, output an integer in one line, indicating the max value of all paths which passes the specific node.
Sample Input
6 13 query 1 query 2 query 3 query 4 query 5 query 6 change 6 1 query 1 query 2 query 3 query 4 query 5 query 6
Sample Output
17 17 17 16 17 17 12 12 12 11 12 12
Source
2017 Multi-University Training Contest - Team 9
题意:
有一颗二叉树,其提供查询和修改两种操作。一是query i即查询所有经过i节点的路径的值的最大值,二是change u x将u节点的值改为x
思路:
这个题目大概需要解决这么几个问题:
1、二叉树的规模太大了,无法直接用数组储存
2、如何寻找经过某节点的路径的最大值
首先解决第一个问题:
由于除了修改的值外,所有节点的值即是其编号,因此可以使用一个map来仅仅储存被修改的值
然后是第二个问题:
通过简单的分析我们可以知道,可以达到最大值的路径必定是以待查询节点向上的某节点的另一子节点的向下走所能达到的最大值,加上待查询节点到这个节点所经过的节点的值加上待查询节点向下走所能达到的最大值。
那么如何得到一个节点向下走所能得到的最大路径?
在保证能走到该节点能达到最深层的前提下尽量向右走即可(因为向下和向右均是较大的值,但是向下增加得更快一点)
需要注意的是每次修改之后被修改节点以上的向下走所能达到的最大值都需要修改。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
int size;
map<int,LL> tree;
map<int,LL> maxn;
#define val(x) (tree.count(x)?tree[x]:x)
#define mvl(x) (x<<1)
//向左下移动
#define mvr(x) (x<<1|1)
//向右下移动
#define mvu(x) (x>>1)
//向上移动
#define from(x) ((x&1)?(x<<1):(x<<1|1))
LL solve(int x)
{
if(x>size) return 0;
if(maxn.count(x)) return maxn[x];
LL ans=0;
int ori=x;
int deepl=0,deepr=0;
while(mvl(ori)<=size)
{
ori=mvl(ori);
++deepl;
}
ori=x;
while((mvr(ori))<=size)
{
ori=(mvr(ori));
++deepr;
}
if(deepl!=deepr) ori=size;
while(ori>=x)
{
ans+=ori;
ori=mvu(ori);
}
//maxn[x]=ans;
return ans;
}
LL found(int x)
{
LL ans=solve(mvr(x))+solve(mvl(x))+val(x);
//cout<<(val(x)+solve(mvr(x))+solve(mvl(x)))<<endl;
int ori=x;
LL goup=0;
while(mvu(x))
{
goup+=val(mvu(x));
if(x&1)
{
x=mvu(x);
ans=max(ans,solve(ori)+goup+solve(mvl(x)));
//cout<<solve(ori)<<' '<<mvl(x)<<' '<<solve(mvl(x))<<' '<<goup<<endl;
}
else
{
x=mvu(x);
ans=max(ans,solve(ori)+goup+solve(mvr(x)));
//cout<<solve(ori)<<' '<<mvr(x)<<' '<<solve(mvr(x))<<' '<<goup<<endl;
}
}
return ans;
}
void change(int a,LL b)
{
maxn[a]=max(solve(mvr(a)),solve(mvl(a)))+b;
tree[a]=b;
while(mvu(a))
{
a=mvu(a);
maxn[a]=max(solve(mvl(a)),solve(mvr(a)))+val(a);
}
}
int main()
{
int n;
int x,a;LL b;
while(cin>>size>>n)
{
maxn.clear();
tree.clear();
string str;
int i;
for(i=0;i<n;i++)
{
cin>>str;
if(str=="query")
{
cin>>x;
cout<<found(x)<<endl;
}
else{
cin>>a>>b;
change(a,b);
}
}
}
return 0;
}