析合树

摘要:
EOF:*l++;}templatevoidrd(T&x){x=0;intf=1,ch=gc();while(ch'9'){if(ch=='-')f=-1;ch=gc);}而(ch˃='0'&&ch˂='9'){x=x*10-'0'+ch;ch=gc();}x*=f;}组分最大值=100000+50;intn,m,a[maxn];namespacermq{intbit[25],lg2[maxn];intmn[25][maxn],mx[25][maxn];voinitit(){bit[0]=1;对于(inti=1;i˂25;++i)bit[i]=bit[i-1]˂˂1;lg2[0]=-1;对于(inti=1;i˃1]+1;对于(int=1;i˂=n;+i)mn[0]=mx[0][i]=a[i];对于(intk=1;bit[k]˂=n;++k){对于(inti=1;i+bit[k]-1˂=n;++i){mn[k][i]=min(mn[k-1][i],mn[k-1][i+bit[k-1]]);mx[k][i]=max(mx[k-1][i],mx[k-1][i+bit[k+1]);}}内联Qmax(intl,intr){intk=lg2[r-l+1];returnmax(mx[k][l],mx[k][r-bit[k]+1]);}内联Qmin(intl,intr){intk=lg2[r-l+1];返回min(mn[k][l],mn[k][r-bit[k]+1]);}}namespaceseg{constantmaxnode=maxn˂˂2;intmn[maxnode],标记[maxnode;inlinevoidchange(intu,intd){mn[u]+=d,标记[u]+=d;}inlinevoidpushdown(intu){if(tag[u]){change(u<˂1,tag[u〕);change(u<˂1|1,tag[u〕);tag[u]=0;}inlinevoidpushup(intu){mn[u]=min(mn[u˂˂1],mn[u˃1;构建(lson);建造;俯卧撑(u);}voidupdate(intu,intl,intr,intql,intqr,intqv){if(l==ql&&r==qr){change(u,qv);return;}intmid=(1+r)˃˃1;下推(u);如果(qrmid)更新(rson、ql、qr、qv);否则{update(lson,ql,mid,qv);update(rson,mid+1,qr,qv);}俯卧撑(u);}intquery(intu,intl,intr){if(l==r)retur
析合树

https://www.cnblogs.com/Paul-Guderian/p/11020708.html

定义

对于一个排列,称其中一个区间([l,r])为连续段若(r-l=max{[l,r]}-min{[l,r]}),即其中元素排序后权值形成一段连续的区间.

对于两个相交的连续段,发现它们的并是连续段,它们的交也是连续段.

所以我们可以找出(O(n))个本源连续段,满足其他所有连续段和本源连续段只有包含关系,且所有连续段都可以被若干本源连续段的并表示.

这样一来,本源连续段的包含关系就形成了一个树的结构,称其为析合树.

其中每个节点是析点或合点,满足

  • 叶子是析点
  • 析点的所有非平凡儿子区间(大小不等于1,也不是全集)都不是连续段
  • 合点的所有非平凡儿子区间都是连续段

如此一来,所有连续段要么是树上的节点,要么是合点的非平凡儿子区间.

许多关于连续段的问题都可以在析合树上解决.

构造

考虑增量构造,从小到大枚举(r),并处理所有右端点为(r)的节点.

考虑维护一个栈,按栈顶向下从右到左的顺序储存所有还没有父亲的节点.

定义当前节点为(now),初始(now=[r,r]).并对栈顶元素重复以下判断.

  • 若栈顶元素是合点,则判断(now)是否能成为它的最后一个儿子(对于合点在建立时纪录它第二个儿子的左端点),若能,则令它为(now),右端点变为(r),弹出栈顶
  • 否则,若(now)和栈顶元素可以构造一个连续段,建立一个新的合点作为它们的父亲,令这个新建的点为(now),弹出栈顶
  • 否则,看是否可以找出栈顶向下的一段连续元素,使得它们共同构成了一个连续段,建立一个新的析点作为他们的父亲,令这个新建的点为(now),弹出这些元素.若不能则退出

分析复杂度,前两种情况都是(O(1))的,第3种情况假如成功,那么复杂度均摊是(O(n))的,但是若失败可能会退化为(O(n^2))

所以可以先求出(L_i)表示以(i)为右端点的最大的连续段的左端点,可以解(L_i)直接判断是否可以成功找到这样的连续段.

那么如何求(L_i)呢,我们可以在(r)增大时对每个(l)维护(max{[l,r]}-min{[l,r]}-(r-l)),则最小值即=0的位置即是连续段的左端点,找到最左边的0就是(L_i)了.(max,min)的部分用单调栈维护即可.

建树部分复杂度(O(n)),求(L_i)复杂度(O(nlog n)),总时间复杂度(O(n log n))

Code

https://www.luogu.com.cn/problem/P4747

求包含([l,r])的最小连续段.

找到([l,l],[r,r])在析合树上的lca,若其为析点,那么答案为lca,若其为合点,那么答案是它们对应儿子构成的区间.

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <vector>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
using namespace std;
inline char gc() {
//	return getchar();
	static char buf[100000],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void rd(T &x) {
	x=0; int f=1,ch=gc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
	x*=f;
} 
const int maxn=100000+50;
int n,m,a[maxn];
namespace rmq {
	int bit[25],lg2[maxn];
	int mn[25][maxn],mx[25][maxn];
	void init() {
		bit[0]=1;
		for(int i=1;i<25;++i) bit[i]=bit[i-1]<<1;
		lg2[0]=-1;
		for(int i=1;i<=n;++i) lg2[i]=lg2[i>>1]+1;
		for(int i=1;i<=n;++i) mn[0][i]=mx[0][i]=a[i];
		for(int k=1;bit[k]<=n;++k) {
			for(int i=1;i+bit[k]-1<=n;++i) {
				mn[k][i]=min(mn[k-1][i],mn[k-1][i+bit[k-1]]);
				mx[k][i]=max(mx[k-1][i],mx[k-1][i+bit[k-1]]);
			}
		}
	}
	inline int Qmax(int l,int r) {
		int k=lg2[r-l+1];
		return max(mx[k][l],mx[k][r-bit[k]+1]);
	}
	inline int Qmin(int l,int r) {
		int k=lg2[r-l+1];
		return min(mn[k][l],mn[k][r-bit[k]+1]);
	}
}
namespace seg {
	const int maxnode=maxn<<2;
	int mn[maxnode],tag[maxnode];
	inline void change(int u,int d) {
		mn[u]+=d,tag[u]+=d;
	}
	inline void pushdown(int u) {
		if(tag[u]) {
			change(u<<1,tag[u]);
			change(u<<1|1,tag[u]);
			tag[u]=0;
		}
	}
	inline void pushup(int u) {
		mn[u]=min(mn[u<<1],mn[u<<1|1]);
	}
	void build(int u,int l,int r) {
		tag[u]=0;
		if(l==r) {
			mn[u]=0;
			return;
		}
		int mid=(l+r)>>1;
		build(lson);
		build(rson);
		pushup(u);
	}
	void update(int u,int l,int r,int ql,int qr,int qv) {
		if(l==ql&&r==qr) {
			change(u,qv);
			return;
		}
		int mid=(l+r)>>1;
		pushdown(u);
		if(qr<=mid) update(lson,ql,qr,qv);
		else if(ql>mid) update(rson,ql,qr,qv);
		else {
			update(lson,ql,mid,qv);
			update(rson,mid+1,qr,qv);
		}
		pushup(u);
	}
	int query(int u,int l,int r) {
		if(l==r) return l;
		int mid=(l+r)>>1;
		pushdown(u);
		if(mn[u<<1]==0) return query(lson);
		else return query(rson);
	} 
}
namespace dct {
	const int maxnode=maxn<<1;
	int ncnt;
	int root;
	int rnk[maxn];
	int L[maxnode],R[maxnode],M[maxnode],typ[maxnode];
	int head[maxnode];
	int dep[maxnode],parent[maxnode][20];
	struct edge {
		int to,nex;
		edge(int to=0,int nex=0):to(to),nex(nex){}
	};
	vector<edge> G;
	inline void addedge(int u,int v) {
		G.push_back(edge(v,head[u])),head[u]=G.size()-1;
	}
	void dfs(int u) {
		for(int i=1;i<20;++i) parent[u][i]=parent[parent[u][i-1]][i-1];
		for(int i=head[u];~i;i=G[i].nex) {
			int v=G[i].to;
			dep[v]=dep[u]+1;
			parent[v][0]=u;
			dfs(v);
		}
	}
	int jump(int u,int k) {
		for(int i=19;~i;--i) if(k>>i&1) {
			u=parent[u][i];
		}
		return u;
	}
	int lca(int u,int v) {
		if(dep[u]>dep[v]) swap(u,v);
		v=jump(v,dep[v]-dep[u]);
		if(u==v) return u;
		for(int i=19;~i;--i) {
			if(parent[u][i]!=parent[v][i]) {
				u=parent[u][i];
				v=parent[v][i];
			}
		}
		return parent[u][0];
	}
 	inline bool judge(int l,int r) {return r-l==rmq::Qmax(l,r)-rmq::Qmin(l,r);}
	void build() {
		static int sta[maxnode],sta1[maxn],sta2[maxn]; int top=0,top1=0,top2=0;
		seg::build(1,1,n);
		memset(head,-1,sizeof(head));
		for(int r=1;r<=n;++r) {
			while(top1&&a[sta1[top1]]<a[r]) {
				seg::update(1,1,n,sta1[top1-1]+1,sta1[top1],-a[sta1[top1]]);
				--top1;
			}
			sta1[++top1]=r;
			seg::update(1,1,n,sta1[top1-1]+1,sta1[top1],a[sta1[top1]]);
			while(top2&&a[sta2[top2]]>a[r]) {
				seg::update(1,1,n,sta2[top2-1]+1,sta2[top2],a[sta2[top2]]);
				--top2;
			}
			sta2[++top2]=r;
			seg::update(1,1,n,sta2[top2-1]+1,sta2[top2],-a[sta2[top2]]);
			int u=++ncnt; L[u]=R[u]=r; rnk[r]=u;
			int mnl=seg::query(1,1,n);
			while(top&&L[sta[top]]>=mnl) {
				if(typ[sta[top]]&&judge(M[sta[top]],r)) {
					addedge(sta[top],u);
					R[sta[top]]=r;
					u=sta[top--];
				}
				else if(judge(L[sta[top]],r)) {
					int v=++ncnt; typ[v]=1;
					L[v]=L[sta[top]],R[v]=r,M[v]=L[u];
					addedge(v,sta[top--]),addedge(v,u);
					u=v;
				}
				else {
					int v=++ncnt; addedge(v,u);
					do addedge(v,sta[top--]); while(!judge(L[sta[top]],r));
					L[v]=L[sta[top]],R[v]=r;
					addedge(v,sta[top--]);
					u=v;
				}
			}
			sta[++top]=u;
			seg::update(1,1,n,1,r,-1);
		}
		root=sta[top];
		dfs(root);
	}
	inline void sol(int l,int r) {
		l=rnk[l],r=rnk[r]; 
		int w=lca(l,r); 
		if(!typ[w]) printf("%d %d
",L[w],R[w]);
		else {
			l=jump(l,dep[l]-dep[w]-1);
			r=jump(r,dep[r]-dep[w]-1);
			printf("%d %d
",L[l],R[r]);
		}
	}
}
int main() {
//	freopen("1.in","r",stdin);
//	freopen("1.out","w",stdout);
	rd(n);
	for(int i=1;i<=n;++i) rd(a[i]);
	rmq::init();
	dct::build();
	rd(m);
	for(int i=1;i<=m;++i) {
		int x,y; rd(x),rd(y);
		dct::sol(x,y);
	}
	return 0;
}

免责声明:文章转载自《析合树》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇高德地图在h5项目中的集成(点标记)Ansible—常用模块下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

flutter json转字符串 字符串转json

=空&&jsonStr。长度˃0){//首先将json字符串转换为jsonMapjson=jsonDecode;//将json转换为modelfinalmodel=UserInfo.fromJson;returnmodel;}returnnull;}...

移动端媒体查询的一些尺寸参考

device-width是设备实际的宽度,不会随着屏幕的旋转而改变,因此并不适合开发响应式网站。比如iphone5s的屏幕分辨率宽为640,由于retina显示策略,当scale设置为1的时候,对应的media中取到的width为320,当scale设置为0.5的时候,width为640,而device-width始终是320。总结1.device-widt...

四、使用ADB命令清除缓存

1、 ADBShell应用程序查看目录结构:adbshells查看系统当前日期:adbselldate查看系统CPU使用情况:adbsHELcat/proc/cpuinfo查看系统内存使用情况:adbshellcat/proc/meminfo显示所有应用程序:adbshelpmlistpackages显示系统自带的应用程序:adshellpmlistpack...

C# 没落了吗?

首先,这个数字--------------------------------------------C#是否正在衰落与微软的整个平台密切相关。近年来,使用C#的人越来越少,这也是因为越来越少的人专门为Microsoft平台开发产品。现在是移动时代,微软基本上错过了互联网和移动互联网这两波浪潮。现在生活不容易。在软件工程中,人们常说“唯一不变的就是改变本身”...

一分钟制作U盘版BT3

一分钟生产BT3U磁盘版本方便、快捷、简单、无效且不可退款。BT3磁盘版本,大约694MB,可以直接烧录,然后用CD引导进入BT3。连接如下:http://ftp.heanet.ie/mirrors/backtrack/bt3-final.isoU磁盘版本Bt3,约783MB,连接为:http://cesium.di.uminho.pt/pub/backtr...