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;
}
posted @ 2025-01-05 19:26  Add_Catalyst  阅读(7)  评论(0)    收藏  举报