lg8936题解

虽然这道题的题目标签有颜色段均摊和并查集,但是这道题的做法与这两个算法并无关系。
考虑从询问的右往左扫描数组。设\(g_i\)表示以第\(i\)个询问为左端点,最大的\(g_i\)\(sol(1,n)=sol(i,g_i)\),则\(f_i=m-g_i+1\)。设\(b\)表示执行完编号为\(1\to m\)操作的数组
\(a_j\)表示扫到\(i\),最大的\(a_j\)使得执行完\(i\to a_j\)的所有操作后\(a_j=b_j\),则答案等于\(\max(a_{1...n})\)
考虑在左添加一个第\(i\)个操作如何更新\(a_j\)。显然添加一个操作的结果是把\(x_i=b_i\)\(l_i\leq i\leq r_i\)的所有\(a_i\)都对\(i\)\(\min\)
考虑把所有数按照\(b_i\)的值分组,并且把每个组内的元素按照在原数组的下标从小到大编号为\(0,1,2,3...\),那么问题转化成:每次对某组的某个区间对\(i\)\(\min\)(这个区间可以二分求),并且求出所有组的数的最大值。
由于所有组的数的最大值等于所有组的所有数取\(\max\),所以可以设\(h_i\)表示第\(i\)组的最大值,可以在线段树上区间修改求出\(h\)
\(a_i\)显然随着\(i\)的降低而降低,所以答案随着\(i\)的减小单调递减。且\(x_i\leq 10^6\),所以可以用桶维护\(x_i\)
然而这道题的空间只有128MB,所以不能用vector存储线段树,而应该用指针和new分配内存,不然会被卡。

#include<bits/stdc++.h>
using namespace std;
#define N 1000010
int n,m,mn[N*4],l[N],r[N],x[N],va[N],ct[N],*g[N],*h[N];
vector<int>v[N];
void mp(int o,int l,int r,int x,int y,int z){
	if(r<x||y<l)
		return;
	if(x<=l&&r<=y){
		mn[o]=max(mn[o],z);
		return;
	}
	int md=(l+r)/2;
	mp(o*2,l,md,x,y,z);
	mp(o*2+1,md+1,r,x,y,z);
}
void pd(int o,int l,int r,int x){
	x=max(x,mn[o]);
	if(l==r){
		va[l]=x;
		return;
	}
	int md=(l+r)/2;
	pd(o*2,l,md,x);
	pd(o*2+1,md+1,r,x);
}
void pd(int p,int o){
	h[p][o*2]=min(h[p][o*2],h[p][o]);
	h[p][o*2+1]=min(h[p][o*2+1],h[p][o]);
	g[p][o*2]=min(g[p][o*2],h[p][o]);
	g[p][o*2+1]=min(g[p][o*2+1],h[p][o]);
}
void mo(int o,int l,int r,int x,int y,int z,int p){
	if(r<x||y<l)
		return;
	if(x<=l&&r<=y){
		h[p][o]=z;
		g[p][o]=min(g[p][o],z);
		return;
	}
	pd(p,o);
	int md=(l+r)/2;
	mo(o*2,l,md,x,y,z,p);
	mo(o*2+1,md+1,r,x,y,z,p);
	g[p][o]=max(g[p][o*2],g[p][o*2+1]);
}
int fd(int o,int l,int r){
	if(l==r)
		return o;
	int md=(l+r)/2;
	return max(fd(o*2,l,md),fd(o*2+1,md+1,r));
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&l[i],&r[i],&x[i]);
		mp(1,1,n,l[i],r[i],x[i]);
	}
	pd(1,1,n,0);
	for(int i=1;i<=n;i++)
		v[va[i]].push_back(i);
	for(int i=1;i<=m;i++){
		l[i]=lower_bound(v[x[i]].begin(),v[x[i]].end(),l[i])-v[x[i]].begin();
		r[i]=lower_bound(v[x[i]].begin(),v[x[i]].end(),r[i]+1)-v[x[i]].begin()-1;
	}
	for(int i=1;i<=1e6;i++)
		if(v[i].size()){
			int sz=fd(1,0,v[i].size()-1);
			g[i]=new int[sz+1];
			h[i]=new int[sz+1];
			for(int j=0;j<=sz;j++)
				g[i][j]=h[i][j]=m+1;
			ct[m+1]++;
		}
	int mx=m+1,lf=0,f;
	unsigned int a1=0,a2=0,a3=0;
	for(int i=m;i;i--){
		if(l[i]>r[i]||!v[x[i]].size())
			f=lf;
		else{
			int sz=v[x[i]].size()-1;
			ct[g[x[i]][1]]--;
			mo(1,0,sz,l[i],r[i],i,x[i]);
			ct[g[x[i]][1]]++;
			while(!ct[mx]&&mx)
				mx--;
			f=m-mx+1;
		}
		a1^=f*i;
		a2+=f*i;
		a3+=f;
		lf=f;
	}
	printf("%u %u %u",a3,a1,a2);
}
posted @ 2023-03-02 11:11  celerity1  阅读(21)  评论(0)    收藏  举报