Description
给出一个
n
个节点的完全二叉树,
query u: 查询所有经过 u 节点路径权值的最大值
Input
多组用例,每组用例首先输入两个整数
Output
对于每个查询,输出结果
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
Solution
先考虑查询操作,令
sum(u)
为从叶子节点到
u
节点路径权值最大值,
然后考虑更新操作对
注意到这里
n
很大,对
Code
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
map<int,ll>sum,val;
int n,q;
int ls(int t)
{
return (t<<1);
}
int rs(int t)
{
return ((t<<1)|1);
}
int get_l(int t)
{
int num=0;
while(ls(t)<=n)t=ls(t),num++;
return num;
}
int get_r(int t,int &m)
{
int num=0;
while(rs(t)<=n)t=rs(t),num++;
m=t;
return num;
}
ll deal(int u)
{
if(u>n)return 0;
if(sum.count(u))return sum[u];
int m;
int L=get_l(u),R=get_r(u,m);
if(L!=R)m=n;
ll ans=0;
while(m!=u)
{
ans+=m;
m>>=1;
}
return ans+u;
}
void update(int t,ll x)
{
val[t]=x;
while(t)
{
sum[t]=max(deal(ls(t)),deal(rs(t)))+(val.count(t)?val[t]:t);
t>>=1;
}
}
ll query(int t)
{
ll ans=deal(ls(t))+deal(rs(t))+(val.count(t)?val[t]:t);
ll res=deal(t);
int flag=t%2;
t>>=1;
while(t)
{
res+=(val.count(t)?val[t]:t);
if(flag)ans=max(ans,res+deal(ls(t)));
else ans=max(ans,res+deal(rs(t)));
flag=t%2;
t>>=1;
}
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
sum.clear(),val.clear();
char op[11];
int u;
ll x;
while(q--)
{
scanf("%s%d",op,&u);
if(op[0]=='q')printf("%I64d\n",query(u));
else
{
scanf("%I64d",&x);
update(u,x);
}
}
}
return 0;
}