CF1290E Cartesian Tree 题解
CF1290E Cartesian Tree 题解
知识点
笛卡尔树,势能线段树。
分析
我们知道,对于一棵笛卡尔树和它的任意一个子树,其大小就是覆盖区间的长度,即 \(R-L+1\)。
那么我们可以考虑把答案转化成 \(\sum_{i=1}^n{R_i} - \sum_{i=1}^n{L_i} + n\) 来求,那么如何维护这个东西呢?
考虑从小到大把数一个个加进去。加入一个数时,笛卡尔树会从中间裂开,左边和右边分别重新建立一棵树,然后树根连到加入到点上,考虑新树相对于原树的变化,就是左边的 \(R\) 对某个数取 \(\min\),右边的 \(L\) 对某个数取 \(\max\),这是势能线段树的基本操作。
然后考虑如何维护变化的排列,我们可以用区间加来解决:假设一个插入的数在完整的排列中为第 \(i\) 位,在当前排列插入后为第 \(j\) 位,那么我们只要先让排列在它左边的数的 \(R\) 全部对 \(j-1\) 取 \(\min\),然后把在它右边的数的 \(L,R\) 全部加 1,最后再把在它右边的数的 \(L\) 全部对 \(j+1\) 取 \(\max\) 即可。
还有一个减少代码长度的方法:由于两端是对称的,我们第一次先求 \(L\),然后把整个排列倒过来,再重复求一次 \(L\),就可以求得 \(R\) 了。
区间加的势能线段树,复杂度 \(O(n\log_2^2{n})\)。
代码
//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define FOR(i,a,b) for(int i(a); i<=(int)(b); ++i)
#define DOR(i,a,b) for(int i(a); i>=(int)(b); --i)
#define EDGE(g,i,x,y) for(int i(g.h[x]),y(g[i].v); ~i; y=g[i=g[i].nxt].v)
using namespace std;
constexpr int N(1.5e5+10);
namespace IOEcat {
#define isD(c) ('0'<=(c)&&(c)<='9')
#define DE(...) E(#__VA_ARGS__,__VA_ARGS__)
struct Icat {
char getc() {
return getchar();
}
template<class T>void operator ()(T &x) {
static bool sign(0);
static char ch(0);
sign=0,x=0;
while(ch=getc(),!isD(ch))if(ch=='-')sign=1;
do x=(x<<1)+(x<<3)+(ch^48);
while(ch=getc(),isD(ch));
if(sign)x=-x;
}
template<class T,class...Types>void operator ()(T &x,Types&...args) {
return (*this)(x),(*this)(args...);
}
} I;
struct Ocat {
void putc(char c) {
putchar(c);
}
template<class T>void operator ()(T x,const char lst='\n') {
static int top(0);
static char st[100];
if(x<0)x=-x,putc('-');
do st[++top]=(x%10)^48,x/=10;
while(x);
while(top)putc(st[top--]);
putc(lst);
}
template<class T,class...Types>void operator ()(const T x,const char lst='\n',const Types...args) {
return (*this)(x,lst),(*this)(args...);
}
} O;
struct Ecat {
template<class T>void operator ()(const char *fmt,const T x) {
cerr<<fmt<<':'<<x<<'.'<<endl;
}
template<class T,class...Types>void operator ()(const char *fmt,const T x,const Types...args) {
while(*fmt^',')cerr<<*fmt++;
return cerr<<':'<<x<<" ,",(*this)(++fmt,args...);
}
} E;
} using namespace IOEcat;
int n;
int a[N],p[N];
ll ans[N];
namespace SEG {
struct Data {
int fx,fc,sx,sc;
ll sum;
Data(int fx=0,int fc=0,int sx=0,int sc=0,ll sum=0):fx(fx),fc(fc),sx(sx),sc(sc),sum(sum) {}
friend Data operator +(Data A,Data B) {
Data C(0,0,0,0,A.sum+B.sum);
if(A.fx==B.fx)C.fx=A.fx,C.fc=A.fc+B.fc,C.sx=max(A.sx,B.sx),C.sc=A.sc+B.sc;
else if(A.fx>B.fx)C.fx=A.fx,C.fc=A.fc,C.sx=max(A.sx,B.fx),C.sc=A.sc+B.fc+B.sc;
else C.fx=B.fx,C.fc=B.fc,C.sx=max(A.fx,B.sx),C.sc=A.fc+A.sc+B.sc;
return C;
}
};
struct Tag {
int t,_t;//对于最值和非最值
Tag(int t=0,int _t=0):t(t),_t(_t) {}
friend Data operator +(Data A,Tag B) {
return Data(A.fx+B.t,A.fc,A.sx+B._t,A.sc,A.sum+(ll)A.fc*B.t+(ll)A.sc*B._t);
}
friend Tag operator +(Tag A,Tag B) {
return Tag(A.t+B.t,A._t+B._t);
}
bool empty() {
return !t&&!_t;
}
};
struct SEG {
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)
struct node {
Data data;
Tag tag;
void down(Tag _tag,bool flag) {
if(!flag)_tag.t=_tag._t;
data=data+_tag,tag=tag+_tag;
}
} tr[N<<2];
void Build(int p=1,int l=1,int r=n) {
tr[p]={Data(),Tag()};
if(l==r)return;
Build(ls,l,mid),Build(rs,mid+1,r);
}
void Up(int p) {
tr[p].data=tr[ls].data+tr[rs].data;
}
void Down(int p) {
if(!tr[p].tag.empty()) {
const bool fl(tr[ls].data.fx>=tr[rs].data.fx),fr(tr[ls].data.fx<=tr[rs].data.fx);
tr[ls].down(tr[p].tag,fl),tr[rs].down(tr[p].tag,fr),tr[p].tag=Tag();
}
}
void Plus(int L,int R,int p=1,int l=1,int r=n) {
if(L<=l&&r<=R)return tr[p].down(Tag(1,1),1);
Down(p);
if(L<=mid)Plus(L,R,ls,l,mid);
if(mid<R)Plus(L,R,rs,mid+1,r);
Up(p);
}
int Count(int L,int R,int p=1,int l=1,int r=n) {
if(L<=l&&r<=R)return tr[p].data.fc+tr[p].data.sc;
Down(p);
if(R<=mid)return Count(L,R,ls,l,mid);
if(mid<L)return Count(L,R,rs,mid+1,r);
return Count(L,R,ls,l,mid)+Count(L,R,rs,mid+1,r);
}
void Change(int x,int d,int p=1,int l=1,int r=n) {
if(l==r)return tr[p].data=Data(d,1,0,0,d),void();
return Down(p),(x<=mid?Change(x,d,ls,l,mid):Change(x,d,rs,mid+1,r)),Up(p);
}
void toMin(int L,int R,int d,int p=1,int l=1,int r=n) {
if(d>=tr[p].data.fx)return;
if(L<=l&&r<=R&&d>tr[p].data.sx)return tr[p].down(Tag(min(d-tr[p].data.fx,0),0),1);
Down(p);
if(L<=mid)toMin(L,R,d,ls,l,mid);
if(mid<R)toMin(L,R,d,rs,mid+1,r);
Up(p);
}
#undef ls
#undef rs
#undef mid
} seg;
} using namespace SEG;
int main() {
#ifdef Plus_Cat
freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
I(n);
FOR(i,1,n)I(a[i]);
FOR(o,0,1) {
seg.Build();
FOR(i,1,n)p[a[i]]=i;
FOR(i,1,n) {
int cnt(p[i]<n?seg.Plus(p[i]+1,n),seg.Count(p[i]+1,n):0);
seg.Change(p[i],i+1);
if(p[i]>1)seg.toMin(1,p[i]-1,i-cnt);
ans[i]+=seg.tr[1].data.sum;
}
reverse(a+1,a+n+1);
}
FOR(i,1,n)O(ans[i]-(ll)i*(i+2),'\n');
return 0;
}