比较显然的树上dp, 但是维护set比较烦
考场上其实自己是定义 \(f[i]\) 是以 \(i\) 结尾, 然后这样的话单次更新根本做不到 \(O(logN)\).
反应实在是太迟钝了,考场想“如果有一种只更新一条链的dp就好了”
结果完全没想到只需变成以 \(i\) 开头就行了.
积累经验吧。不要气馁。
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
#define G(i,r,l) for(int i(r);i>=l;--i)
#define int ll
using namespace std;
using ll = long long;
const int N = 1e6+5,ninf = -0x3f3f3f3f3f3f3f3f;
int n,f[N]; //f[i]:以 i 为开头的答案
multiset<int,greater<int>> tr[N];
void insert(int x,int val){
if(tr[x].size() && *tr[x].begin() >= val){
tr[x].emplace(val);
return ;
} tr[x].emplace(val);
while(x){
if(tr[x].empty()) return ;
int tmp;
if(x*2<1000000) tmp = max(f[x*2], f[x*2+1]) + *tr[x].begin();
else tmp = *tr[x].begin();
if(tmp<=f[x]) return;
if(f[x] != 0) tr[0].erase(f[x]);
f[x] = max(0ll,tmp);
if(f[x] != 0) tr[0].insert(f[x]);
x>>=1;
}
}
void del(int x,int val){
if(tr[x].size() && *tr[x].begin() != val){
tr[x].erase(val);
return ;
} tr[x].erase(val);
while(x){
if(tr[x].empty()){
if(f[x] != 0) tr[0].erase(f[x]);
f[x] = 0;
}
else{
int tmp;
if(x*2>1000000) tmp = *tr[x].begin();
else tmp = max(f[x*2], f[x*2+1]) + *tr[x].begin();
if(tmp == f[x]) return ;
if(f[x] != 0) tr[0].erase(f[x]);
f[x] = max(0ll,tmp);
if(f[x]!=0) tr[0].insert(f[x]);
}x>>=1;
}
}
signed main(){
// freopen("prob.in","r",stdin);freopen("prob.out","w",stdout);
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n;
tr[0].emplace(0);
while(n--){
int op,p,b;
cin>>op>>p>>b;
if(op==1) insert(p,b);
else del(p,b);
cout<<*tr[0].begin()<<"\n";
}
return 0;
}
/*
T
n,m,k,st
u,v,w
think twice, code once.
check your code:
array memory
testing sentence
*/
标签:tmp,set,return,val,int,C240817D,tr,dp
From: https://www.cnblogs.com/superl61/p/18364513