LOJ #3277. 「JOISC 2020 Day3」星座 3 (笛卡尔树+线段树合并)
笛卡尔树好神奇啊!
我们考虑对白色区域维护以最大值为中点笛卡尔树,然后考虑怎么合并左右区间:
令 $f[h]$ 表示最高高度为 $h$ 的最大保留权和,v 表示当前笛卡尔树节点的权值.
考虑如何合并左右区间:
显然,如果要将 $f[y]$ 贡献给 $f[x]$,那么 $x$ 要大于 $y.$
我们将左右区间的所有状态分成大于等于 $v$ 和小于等于 $v$.
因为要求任意不包含白点的矩阵只能有一个星星,所以左面小于等于 $v$ 的可以完全贡献给右面大于等于 $v$ 的(左面大于 $v$ 的贡献不了)
这个在线段树上就是一个区间标记下传.
然后对于小于 $v$ 的情况比较难处理,但是我们发现笛卡尔树中父亲的权值大于等于当前权值,所以小于 $v$ 的所有情况只保留一个就行(既左max+右max 赋给 $f[v-1]$)
然后来一个线段树合并合并一下状态就行.
code:
#include <bits/stdc++.h>
#define N 200007
#define ll long long
#define lson s[x].ls
#define rson s[x].rs
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int tot,n,top;
int ch[N][2],a[N],val[N],sta[N],size[N],RT[N];
int newnode() { return ++tot; }
struct data { int h,c; data(int h=0,int c=0):h(h),c(c){} };
struct node { int ls,rs;ll ma,ad; }s[N*80];
vector<data>ge[N];
void mark(int x,ll v) { s[x].ma+=v,s[x].ad+=v; }
void pushdown(int x)
{
if(s[x].ad)
{
if(lson) mark(lson,s[x].ad);
if(rson) mark(rson,s[x].ad);
s[x].ad=0;
}
}
void update(int &x,int l,int r,int p,ll v)
{
if(!x) x=newnode();
s[x].ma=max(s[x].ma,v);
if(l==r) return;
int mid=(l+r)>>1;
pushdown(x);
if(p<=mid) update(lson,l,mid,p,v);
else update(rson,mid+1,r,p,v);
}
ll query(int x,int l,int r,int L,int R)
{
if(!x) return 0;
if(l>=L&&r<=R) return s[x].ma;
pushdown(x);
int mid=(l+r)>>1; ll re=0;
if(L<=mid) re=max(re,query(lson,l,mid,L,R));
if(R>mid) re=max(re,query(rson,mid+1,r,L,R));
return re;
}
void addv(int x,int l,int r,int L,int R,ll v)
{
if(!x) return;
if(l>=L&&r<=R) { mark(x,v); return; }
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid) addv(lson,l,mid,L,R,v);
if(R>mid) addv(rson,mid+1,r,L,R,v);
s[x].ma=max(s[lson].ma,s[rson].ma);
}
int merge(int x,int y)
{
if(!x||!y) return x+y;
pushdown(x),pushdown(y);
int now=newnode();
s[now].ma=max(s[x].ma,s[y].ma);
s[now].ls=merge(s[x].ls,s[y].ls);
s[now].rs=merge(s[x].rs,s[y].rs);
return now;
}
void dfs(int x)
{
size[x]=1;
if(ch[x][0]) dfs(ch[x][0]),size[x]+=size[ch[x][0]];
if(ch[x][1]) dfs(ch[x][1]),size[x]+=size[ch[x][1]];
}
void mer(int x,int y,int tmp)
{
ll a=query(RT[x],0,n,0,tmp);
ll b=query(RT[y],0,n,0,tmp);
addv(RT[x],0,n,tmp,n,b);
addv(RT[y],0,n,tmp,n,a);
ll c=query(RT[x],0,n,0,tmp-1);
ll d=query(RT[y],0,n,0,tmp-1);
update(RT[x],0,n,tmp-1,c+d);
RT[y]=merge(RT[x],RT[y]);
}
void solve(int x)
{
for(int i=0;i<ge[x].size();++i)
update(RT[x],0,n,ge[x][i].h,ge[x][i].c);
if(ch[x][0])
solve(ch[x][0]),mer(ch[x][0],x,a[x]);
if(ch[x][1])
solve(ch[x][1]),mer(ch[x][1],x,a[x]);
}
int main()
{
// setIO("input");
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n;++i)
{
while(top&&a[i]>=a[sta[top]])
ch[i][0]=sta[top],--top;
if(top) ch[sta[top]][1]=i;
sta[++top]=i;
}
int rt=sta[1],m;
ll t=0;
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
ge[x].push_back(data(y,c));
t+=(ll)c;
}
dfs(rt);
solve(rt);
printf("%lld\n",t-query(RT[rt],0,n,0,n));
return 0;
}

浙公网安备 33010602011771号