• P4690


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

    区间修改怎么做?观察 (prv) 的变化,发现 ((l,r]) 内的元素 (i) 都有 (prv_i=i-1),依据这个特殊性开始搞事情。那对某个区间,满足 (iin[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
    ",ans[i]);
    	return 0;
    }
    

    好像并不是很难的吼)

    珍爱生命,远离抄袭!
  • 相关阅读:
    8.14-T1村通网(pupil)
    8.10-Day2T3 镇守府
    8.10-Day2T2 吃喝大法好
    8.10-Day2T1最小值
    8.10-DayT3游走(wander)
    8.10-Day1T2圈(circle)
    8.10-Day1T1-数字(number)
    bzoj2462: [BeiJing2011]矩阵模板
    8.7-Day1T1
    k8s高可用部署后续:SLB
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/solution-p4690.html
Copyright © 2020-2023  润新知