通过一个点的最大权值的链可以通过维护每个点到叶子的最大权值得到,方法就是一直把这个点向上提。
因此考虑维护每个点到叶子的最大权值
f
。
如果
往左走:
an=x2n
,
Sn=x(2n−1)
。
往右走:
an=2an−1+1
an+1=2an−1+2
an+1=(x+1)2n
Sn+n=(x+1)(2n−1)
Sn=(x+1)(2n−1)−n
作差得
Sn=x(2n−1)−(x+1)(2n−1−1)+n−1=x2n−1−2n−1+n=(x−1)2n+n≥0
。
所以一直往左走肯定比一直往右走高,所以从
n
点开始往上移。
每发生一次修改,可以向上维护一条链的 map
中维护就行了。
#include<bits/stdc++.h>
#define ls(x) (x<<1)
#define rs(x) ((x)<<1|1)
using namespace std;
typedef long long ll;
unordered_map<int,ll> f(3500000),val(3500000);
int n;
ll cal(int x)
{
if(x>n) return 0;
if(f.count(x)) return f[x];
int t=x,cl=0,cr=0;
while(t<=n) ++cl,t=ls(t);
t=x;
while(t<=n) ++cr,t=rs(t);
t>>=1;
if(cr!=cl) t=n;
ll res=0;
while(t>=x) res+=t,t>>=1;
return res;
}
void modify(int u,ll x)
{
val[u]=x;
while(u>=1)
{
f[u]=max(cal(ls(u)),cal(rs(u)))+(val.count(u)?val[u]:u);
u>>=1;
}
}
ll query(int x)
{
ll res=cal(ls(x))+cal(rs(x))+(val.count(x)?val[x]:x);
ll d=max(cal(ls(x)),cal(rs(x)))+(val.count(x)?val[x]:x);
while((x>>1)>=1)
{
bool L=(x&1)?1:0;
x>>=1;
d+=val.count(x)?val[x]:x;
res=max(res,d+(L?cal(ls(x)):cal(rs(x))));
}
return res;
}
int main()
{
int m;
while(~scanf("%d%d",&n,&m))
{
f.clear();val.clear();
char op[10];
while(m--)
{
scanf("%s",op);
if(op[0]=='q')
{
int x;scanf("%d",&x);
printf("%I64d\n",query(x));
}
else
{
int u;ll x;
scanf("%d%I64d",&u,&x);
modify(u,x);
}
}
}
return 0;
}