洛谷P4690 [Ynoi2016] 镜中的昆虫

题目描述

给定一个长度为 \(n\) 的序列 \(a\),有 \(m\) 次操作。共有两种操作:

  • 1 l r x,将 \([l,r]\) 区间赋值为 \(x\)
  • 2 l r,求 \([l,r]\) 中出现了多少种不同的数。

数据范围:\(1\le n,m\le 10^5\)\(a_i\le 10^9\)

时间范围:\(1500\operatorname{ms}\)

Solution

直接暴力是 \(O(n^2)\) 的,显然可以通过本题,不需要考虑优化。

对于每个数,求出上一个与这个数相同的位置,定为 \(pre\),没有则为 \(0\)

对于区间赋值,我们发现当我们会令 \(\forall i\in(l,r],pre_i\leftarrow i-1\),对于 \(i=l\) 特判即可。

同时我们可以发现,当修改位于 \([l,r]\) 中的元素时,与它相同的下一个元素的 \(pre\) 也会变;同时颜色与 \(x\) 相同的位置 \(>r\) 的第一个元素的 \(pre\) 也会变。特判即可。

这一步时间复杂度为 \(O(n)\)大佬们都写了我就不证了。

那么问题转化为求 \(\sum_{i=l}^{r}[pre_i<l]\),三维数点即可,时间复杂度为 \(O(n\log^2 n)\)

Code

#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
const int maxn=200010,maxq=1000010;
typedef pair<int,int> PII;
struct Data{
	int x,y,z,k,d,ans;
	inline Data(){}
	inline Data(int _x,int _y,int _z,int _k,int _d){x=_x;y=_y;z=_z;k=_k;d=_d;ans=0;}
	inline bool operator<(const Data &da)const{return x!=da.x?x<da.x:(y!=da.y?y<da.y:z<da.z);}
}q[maxq],w[maxq/2];
struct Operation{
	int opt,l,r,x;
}p[maxn];
int pre[maxn],n,m,tot,a[maxn],b[maxn],cnt,ans[maxn];
inline bool cmpy(const Data &d1,const Data &d2){return d1.y!=d2.y?d1.y<d2.y:d1.z<d2.z;}
struct Color{
	set<PII>col,v[maxn];
	inline void Split(int k){
		set<PII>::iterator it=col.lower_bound(make_pair(k+1,0));
		int r=it->first-1;--it;
		int l=it->first;
		if(k==r)return;
		int c=it->second;
		col.erase(it);
		col.insert(make_pair(l,c));col.insert(make_pair(k+1,c));
		v[c].erase(make_pair(l,r));
		v[c].insert(make_pair(l,k));v[c].insert(make_pair(k+1,r));
	}
	inline void Insert(int l,int r,int c,int t){
		Split(l-1);Split(r);
		for(set<PII>::iterator it=col.lower_bound(make_pair(l,0));it->first<=r;){
			int x=it->first,y=it->second;
			++it;int z=it->first-1;
			col.erase(make_pair(x,y));
			v[y].erase(make_pair(x,z));
			if(x==l){
				int e=(--(v[c].upper_bound(make_pair(x,0))))->second;
				if(pre[x]!=e){
					q[++tot]=Data(t,x,pre[x],0,-1);
					pre[x]=e;
					q[++tot]=Data(t,x,pre[x],0,1);
				}
			}
			else{
				if(pre[x]!=x-1){
					q[++tot]=Data(t,x,pre[x],0,-1);
					pre[x]=x-1;
					q[++tot]=Data(t,x,pre[x],0,1);
				}
			}
			x=z+1;
			z=(v[y].lower_bound(make_pair(x,0)))->first;
			int e=(--v[y].lower_bound(make_pair(l,0)))->second;
			if(z>r&&z<=n&&pre[z]!=e){
				q[++tot]=Data(t,z,pre[z],0,-1);
				pre[z]=e;
				q[++tot]=Data(t,z,pre[z],0,1);
			}
		}
		set<PII>::iterator it=v[c].lower_bound(make_pair(r+1,0));
		int x=it->first;
		if(x<=n&&pre[x]!=r){
			q[++tot]=Data(t,x,pre[x],0,-1);
			pre[x]=r;
			q[++tot]=Data(t,x,pre[x],0,1);
		}
		v[c].insert(make_pair(l,r));
		col.insert(make_pair(l,c));
		x=r+1;
		if(x<=n){
			it=col.lower_bound(make_pair(x,0));
			int y=it->second;
			int e=(--v[y].lower_bound(make_pair(x,0)))->second;
			if(pre[x]!=e){
				q[++tot]=Data(t,x,pre[x],0,-1);
				pre[x]=e;
				q[++tot]=Data(t,x,pre[x],0,1);
			}
		}
	}
}color;
struct TreeArray{
	#define lowbit(x) (x&-x)
	int tr[maxn];
	inline void add(int x,int d){++x;while(x<maxn)tr[x]+=d,x+=lowbit(x);}
	inline int ask(int x){++x;int ans=0;while(x)ans+=tr[x],x-=lowbit(x);return ans;}
	#undef lowbit
}BIT;
inline void CDQ(int l,int r){
	if(l>=r)return;
	int mid=(l+r)>>1;
	CDQ(l,mid);CDQ(mid+1,r);
	int i=l,j=mid+1,k=0;
	bool flag=(l!=1||r!=tot);
	while(i<=mid&&j<=r){
		if(q[i].y<=q[j].y){if(q[i].k==0)BIT.add(q[i].z,q[i].d);if(flag)w[k++]=q[i];++i;}
		else{if(q[j].k==1)q[j].ans+=BIT.ask(q[j].z);if(flag)w[k++]=q[j];++j;}
	}
	while(i<=mid){if(q[i].k==0)BIT.add(q[i].z,q[i].d);if(flag)w[k++]=q[i];++i;}
	while(j<=r){if(q[j].k==1)q[j].ans+=BIT.ask(q[j].z);if(flag)w[k++]=q[j];++j;}
	for(i=l;i<=mid;++i)if(q[i].k==0)BIT.add(q[i].z,-q[i].d);
	if(flag)for(int i=0;i<k;++i)q[i+l]=w[i];
}
FILE *read=stdin,*write=stdout;
int main(){
	fscanf(read,"%d%d",&n,&m);
	for(int i=1;i<=n;++i)fscanf(read,"%d",&a[i]),b[++cnt]=a[i];
	for(int i=1;i<=m;++i){
		fscanf(read,"%d%d%d",&p[i].opt,&p[i].l,&p[i].r);
		if(p[i].opt==1)fscanf(read,"%d",&p[i].x),b[++cnt]=p[i].x;
	}
	sort(b+1,b+cnt+1);
	cnt=unique(b+1,b+cnt+1)-b-1;
	for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
	for(int i=1;i<=m;++i)if(p[i].opt==1)p[i].x=lower_bound(b+1,b+cnt+1,p[i].x)-b;
	for(int i=1;i<=cnt;++i)
		color.v[i].insert(make_pair(0,0));
	for(int i=1;i<=n;++i){
		pre[i]=(--color.v[a[i]].end())->second;
		q[++tot]=Data(0,i,pre[i],0,1);
		color.v[a[i]].insert(make_pair(i,i));
		color.col.insert(make_pair(i,a[i]));
	}
	for(int i=1;i<=cnt;++i)
		color.v[i].insert(make_pair(n+1,0));
	color.col.insert(make_pair(0,0));
	color.col.insert(make_pair(n+1,n+1));
	for(int i=1;i<=m;++i){
		if(p[i].opt==1)
			color.Insert(p[i].l,p[i].r,p[i].x,i);
		else{
			q[++tot]=Data(i,p[i].r,p[i].l-1,1,1);
			q[++tot]=Data(i,p[i].l-1,p[i].l-1,1,-1);
		}
	}
	sort(q+1,q+tot+1);
	CDQ(1,tot);
	for(int i=1;i<=tot;++i)
		if(q[i].k)ans[q[i].x]+=q[i].ans*q[i].d;
	for(int i=1;i<=m;++i)
		if(p[i].opt==2)fprintf(write,"%d\n",ans[i]);
	return 0;
}
posted @ 2021-05-28 19:12  7103  阅读(292)  评论(0)    收藏  举报