P4690 - 镜中的昆虫 题解

先考虑单点修改怎么做。一个套路是,数区间里面所有第一次出现的数,形式化的表示是 \(i\in[l,r],prv_i<l\)。那这是个二维数点了,要是单点修改就动态二维数点上 cdq,至于如何维护 \(prv\) 那就很 trivial 了,set 乱搞。

区间修改怎么做?观察 \(prv\) 的变化,发现 \((l,r]\) 内的元素 \(i\) 都有 \(prv_i=i-1\),依据这个特殊性开始搞事情。那对某个区间,满足 \(i\in[l,r],i-1<l\) 的元素仅可能是 \(i=l\),那就判一判就可以了,这很 trivial。于是就是要对 \(l\) 们展开维护。

那么每次区间修改,把这个区间里原本的 \(l\) 的信息都要删除。怎么快速删除?其实不难想到暴力删除复杂度是对的,因为每次修改只会增加一个 \(l\),那删除的次数也必定不超过修改的次数,这是个简单的势能分析。同时在删除、添加的时候,还要实时维护(原本)以它为前驱的后面的元素,不难发现对每个位置最多有一个,复杂度也是不用担心的。那对任意位置找前驱 / 后继就对每个值维护位置的 set,但是值是批量批量修改的怎么办呢。再开个 set 记录相等段们,然后把区间的代表元(\(l\))扔进之前的那个 set 即可。

搞着搞着搞出一个动态二位数点的操作序列,最后对着这个序列 cdq 一遍即可。复杂度二次对数。虽然这个操作序列异常的长(可能 \(10n\) 左右吧),但还是跑得很快,大概是 cdq 和 BIT 常数实在太小了。

但是这题莫名卡空间,理论上我的空间复杂度是线性(又称线性空间)但还是过不去。我采取了一些卡空间手段(但是只有最后一步起到决定性作用):把 int 能压成 short 就压,甚至可以压到 bool / signed char;把装 3 个 1e6 级别的 intpair<pair<int,int>,int> 用一个 long long 压缩起来然后解压;cdq 的时候不在里面开部分操作序列的 vector,开到外面,并且换成数组。

code(细节有一点点(真的不是亿点点)多(set 维护的题就这样),写了 4k,但是卡空间不算的话是一遍过了啊)
#include<bits/stdc++.h>
using namespace std;
#define X x()
#define Y y()
#define Z z()
#define pb push_back
const int inf=999999;
int lowbit(int x){return x&-x;}
const int N=100010,QU=100010;
int n,qu;
int a[N];
struct query{
	int tp,l,r,x;
}qry[QU];
vector<int> nums;
void discrete(){
	sort(nums.begin(),nums.end());
	nums.resize(unique(nums.begin(),nums.end())-nums.begin());
	for(int i=1;i<=n;i++)a[i]=lower_bound(nums.begin(),nums.end(),a[i])-nums.begin()+1;
	for(int i=1;i<=qu;i++)qry[i].x=lower_bound(nums.begin(),nums.end(),qry[i].x)-nums.begin()+1;
}
set<int> st[N+QU];
struct query0{
	bool add;int x,y;signed char v;int id;
	friend bool operator<(query0 z,query0 w){return z.x==w.x?(z.y<w.y):(z.x<w.x);}
};
vector<query0> qry0;
struct tup{
	unsigned long long zip;
	tup(int x,int y,int z){zip=(1ll*x<<40)+(1ll*y<<20)+z;}
	int x()const{return zip>>40;}
	int y()const{return zip>>20&((1<<20)-1);}
	int z()const{return zip&((1<<20)-1);}
	friend bool operator<(tup x,tup y){return x.zip<y.zip;}
};
set<tup> rg;
set<tup>::iterator in(int x){
	set<tup>::iterator fd=rg.upper_bound(tup(x,inf,0));
	return --fd;
}
int ans[QU];
int prv[N];
int tor(int l){return l==0?l:in(l)->Y;}
void delblk(int l,int r,int x){//updlist: st(pos), query0, rg, prv
	st[x].erase(l);
	qry0.pb(query0({1,l,prv[l],-1,0}));
	set<int>::iterator fd=st[x].upper_bound(l);
	if(fd!=st[x].end()){
		qry0.pb(query0({1,*fd,prv[*fd],-1,0}));
		set<int>::iterator fd0=fd--;
		qry0.pb(query0({1,*fd0,prv[*fd0]=tor(*fd),1,0}));
	}
}
void addblk(int l,int r,int x){//updlist: st(pos), query0, rg, prv
	st[x].insert(l);rg.insert(tup(l,r,x));
	set<int>::iterator fd=st[x].lower_bound(l);
	qry0.pb(query0({1,l,prv[l]=tor(*--fd),1,0}));
	fd++;fd++;
	if(fd!=st[x].end()){
		qry0.pb(query0({1,*fd,prv[*fd],-1,0}));
		qry0.pb(query0({1,*fd,prv[*fd]=r,1,0}));
	}
}
struct bitree{
	int cnt[N];
	bitree(){memset(cnt,0,sizeof(cnt));}
	void add(int x,int v){
		while(x<=n+1)cnt[x]+=v,x+=lowbit(x);
	}
	int Cnt(int x){
		int res=0;
		while(x)res+=cnt[x],x-=lowbit(x);
		return res;
	}
}bit;
query0 v[10*N];int tail;
void cdq(int l=0,int r=qry0.size()-1){
	if(l==r)return;
	int mid=l+r>>1;
	cdq(l,mid),cdq(mid+1,r);
	tail=0;
	for(int i=l;i<=mid;i++)if(qry0[i].add==1)v[tail++]=qry0[i];
	for(int i=mid+1;i<=r;i++)if(qry0[i].add==0)v[tail++]=qry0[i];
	stable_sort(v,v+tail);
	for(int i=0;i<tail;i++){
		int add=v[i].add,x=v[i].y,v0=v[i].v,id=v[i].id;
		if(add)bit.add(x+1,v0);
		else ans[id]+=v0*bit.Cnt(x+1);
	}
	for(int i=0;i<tail;i++){
		int add=v[i].add,x=v[i].y,v0=v[i].v;
		if(add)bit.add(x+1,-v0);
	}
}
int main(){
	cin>>n>>qu;
	for(int i=1;i<=n;i++)scanf("%d",a+i),nums.pb(a[i]);
	for(int i=1;i<=qu;i++){
		scanf("%d%d%d",&qry[i].tp,&qry[i].l,&qry[i].r);
		if(qry[i].tp==1)scanf("%d",&qry[i].x),nums.pb(qry[i].x);
	}
	discrete();
	for(int i=1;i<=nums.size();i++)st[i].insert(0);//很好的 trick! 
	for(int i=1;i<=n;i++){
		qry0.pb(query0({1,i,prv[i]=*--st[a[i]].end(),1,0}));
		rg.insert(tup(i,i,a[i]));
		st[a[i]].insert(i);
	}
	int ask=0;
	for(int i=1;i<=qu;i++){
		int tp=qry[i].tp,l=qry[i].l,r=qry[i].r,x=qry[i].x;
		if(tp==1){//updlist: st(pos), query0, rg, prv
			set<tup>::iterator pl=in(l),pr=in(r);
			tup PL=*pl,PR=*pr;
			vector<tup> del;
			for(set<tup>::iterator j=pl;;j++){
				delblk(j->X,j->Y,j->Z),del.pb(*j);
				if(j==pr)break;
			}
			for(int j=0;j<del.size();j++)rg.erase(del[j]);
			if(l!=PL.X)addblk(PL.X,l-1,PL.Z);
			addblk(l,r,x);
			if(r!=PR.Y)addblk(r+1,PR.Y,PR.Z);
		}
		else{
			ask++;
			tup pl=*in(l);
			ans[ask]=l!=pl.X;
			qry0.pb(query0({0,r,l-1,1,ask})),qry0.pb(query0({0,l-1,l-1,-1,ask}));
		}
	}
	cdq();
	for(int i=1;i<=ask;i++)printf("%d\n",ans[i]);
	return 0;
}

好像并不是很难的吼)

posted @ 2021-07-22 13:39  ycx060617  阅读(104)  评论(2编辑  收藏  举报