• 【历史版本线段树】【2019杭州集训12.08】漏网之鱼(escape)


    Description

    在这里插入图片描述
    n,Q<=1e6n,Q<=1e6

    Solution

    • 基础线段树?
    • 首先考虑固定一个端点,维护所有另一个端点的mex。
    • 根据固定的端点的不同是两种截然不同的做法。

    历史版本查询线段树

    • 简单来说就是记录一个time,将贡献表示成ktime+bk*time+b的一个一次函数。
    • 对于修改的tag也是类似的一个一次函数。

    固定右端点

    • 每一个mex的影响区间是单调的。
    • 可以动态维护一个单调栈。
    • 单调栈的修改次数是有限的。修改的时候可以用线段树二分。
    • 同样维护历史查询的线段树

    固定左端点

    • 用一个线段树维护右端点对应的mex。
    • 考虑左端点ll往右移的时候,ala_l的下一个出现的位置之前的所有位置mex都会与ala_l取min。
    • 然后我们可以发现由于整个序列的mex是单调的,会分成很多个块,我们暴力对每一个整块取min实际上是可以的,也就是每一次修改mex相同的区间。
    • 记录一个区间的最大值,以及区间的mex是否相同即可。
    • 对于每一个位置r我们要求所有的l对于它的mex,并且有一些连续的l对于这个r的mex都是一样的,这实际上是一个查询历史版本的线段树。
    • 对于一个mex,在r上,它的贡献可以被表示成ktime+bk*time+b,即一个关于当前的时间(左端点的位置)的一次函数。
    • 对于修改(区间赋值)的时候,可以记一个tag表示修改成什么,tagk为对于k的贡献,tagb为对于b的贡献,即贡献为(newsumsum)(timenowtime)(newsum-sum)*(time-nowtime)。注意到由于整个区间在这之前已经完全一样了,所以我们tagk和tagb实际可以表示成增量newsumsumnewsum-sum,修改的时候再乘上区间的长度,这样就可以直接把tagk和tagb下传了。
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define maxn 1000005
    #define maxt 5000005
    #define LL long long 
    using namespace std;
    
    int type,n,m,Q,i,j,k,now,tot,a[maxn],nex[maxn],L[maxn],R[maxn];
    struct query{int x,i,t;} q[maxn*2];
    int cmp(query a,query b){return a.x<b.x;}
    int mex[maxn],bz[maxn];
    LL ans[maxn];
    
    void read(int &x){
    	x=0; char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar());
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    }
    
    LL tk[maxt],tb[maxt],tagk[maxt],tagb[maxt]; int mx[maxt],tag[maxt],sm[maxt];
    void upd(int x){
    	tk[x]=tk[x<<1]+tk[x<<1^1];
    	tb[x]=tb[x<<1]+tb[x<<1^1];
    	mx[x]=max(mx[x<<1],mx[x<<1^1]);
    	if (sm[x<<1]&&sm[x<<1^1]) sm[x]=mx[x<<1]==mx[x<<1^1];
    	else sm[x]=0;
    }
    
    void maketree(int x,int l,int r){
    	tag[x]=-1;
    	if (l==r) {
    		tk[x]=mx[x]=mex[l],sm[x]=1;
    		return;
    	}
    	int mid=(l+r)>>1;
    	maketree(x<<1,l,mid),maketree(x<<1^1,mid+1,r);
    	upd(x);
    }
    
    void downtag(int x,int l,int r){
    	tk[x]+=tagk[x]*(r-l+1),tb[x]+=tagb[x]*(r-l+1),mx[x]=tag[x];
    	if (l<r){
    		tagk[x<<1]+=tagk[x],tagb[x<<1]+=tagb[x];
    		tagk[x<<1^1]+=tagk[x],tagb[x<<1^1]+=tagb[x];
    		tag[x<<1]=tag[x<<1^1]=tag[x];
    	}
    	tag[x]=-1,tagk[x]=tagb[x]=0;
    }
    
    void change(int x,int l,int r,int ll,int rr,int d){
    	if (tag[x]!=-1) downtag(x,l,r);
    	if (l>rr||r<ll||mx[x]<=d) return;
    	if (ll<=l&&r<=rr&&sm[x]){
    		tagk[x]=d-mx[x],tagb[x]=-1ll*now*(d-mx[x]),tag[x]=d;
    		downtag(x,l,r);
    		return;
    	}
    	int mid=(l+r)>>1;
    	change(x<<1,l,mid,ll,rr,d),change(x<<1^1,mid+1,r,ll,rr,d);
    	upd(x);
    }
    
    LL find(int x,int l,int r,int ll,int rr){
    	if (tag[x]!=-1) downtag(x,l,r);
    	if (l>rr||r<ll) return 0;
    	if (ll<=l&&r<=rr) return tk[x]*now+tb[x];
    	int mid=(l+r)>>1;
    	return find(x<<1,l,mid,ll,rr)+find(x<<1^1,mid+1,r,ll,rr);
    }
    
    int main(){
    	read(type),read(n);
    	for(i=1;i<=n;i++) {
    		read(a[i]);
    		if (a[i]>n) a[i]=n+1;
    	}
    	for(i=n;i>=1;i--) {
    		if (bz[a[i]]) nex[i]=bz[a[i]]; else nex[i]=n+1;
    		bz[a[i]]=i;
    	}
    	read(Q);
    	for(i=1;i<=Q;i++) {
    		read(k),L[i]=k; if (k-1) tot++,q[tot].x=k-1,q[tot].t=-1,q[tot].i=i;
    		read(k),R[i]=k; tot++,q[tot].x=k,q[tot].t=1,q[tot].i=i;
    	}
    	sort(q+1,q+1+tot,cmp);
    	memset(bz,0,sizeof(bz));
    	for(k=0,i=1;i<=n;i++) {
    		for(bz[a[i]]=1;bz[k];k++);
    		mex[i]=k;
    	}
    	maketree(1,1,n),k=1;
    	for(now=1;now<=n;now++) {
    		for(;k<=tot&&q[k].x==now;k++) ans[q[k].i]+=find(1,1,n,L[q[k].i],R[q[k].i])*q[k].t;
    		if (now+1<nex[now]) change(1,1,n,now+1,nex[now]-1,a[now]);
    		change(1,1,n,now,now,0);
    	}
    	for(i=1;i<=Q;i++) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    Django学习笔记之Cookie、Session和自定义分页
    sass表达式前后出现空格
    render总结
    vue双向绑定补充说明方法
    mutation与action
    keep-alive使用笔记
    this指向 一般函数与箭头函数
    vue-router原理分析
    history新增方法
    常用阻止ajax缓存方法集锦
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090901.html
Copyright © 2020-2023  润新知