zoukankan      html  css  js  c++  java
  • 6911. 【2020.12.01提高组模拟】莫队

    一个序列,定义无重区间为没有重复的数的区间。两种操作:

    1. (a_x)改为(y)
    2. 询问区间([x,y])中有多少个无重子区间。

    (n,mle 2*10^5)


    按照套路求出每个位置前面第一个相同的位置,记为(lst_i),对于一个询问([L,R]),答案为(sum_{i=L}^R i-max(max_{j=L}^{i}lst_j,L-1))

    相当于要求([L,R])的前缀(max)的和。

    可以规定(lst_L=L-1),这样就不用特别考虑(L-1)的影响,甚至可以直接写作(sum_{i=L}^R i-max_{j=1}^ilst_j)

    考虑暴力,相当于一个数(x),初始为(L-1),从(L)做到(R),每次(x o max(x,a_i))(ll称之为复合),并且做一次加(x)的贡献。记这个东西为(query(L,R,x))

    先说个(O(nlg^2n))的做法:

    用线段树维护。考虑(query(L,R,x)),如果(x>mx(L,mid)),则((mid-l+1)*x+query(mid+1,R,x));否则(query(l,mid,x)+query(mid+1,R,mx(L,mid)))。可以发现(query(mid+1,R,mx(L,mid)))已经和(x)无关了,所以可以预处理(f(L,R)=query(mid+1,R,mx(L,mid)))

    在update的时候花(O(lg ))时间维护每一个有影响的(f(L,R)),于是一次修改时间复杂度(O(lg^2))

    询问的时候需要找出(O(lg))子区间然后进行(query)操作,(query)执行一次是(O(lg)),所以查询一次时间复杂度(O(lg^2))

    再说ll的(O(nlg n))爆标做法:

    对于每个时间,按照序列从前往后做,一路取前缀(max)。(如果是询问时间可以将(lst_{L})变为(L-1),变成从(1)开始的前缀max)

    把时间变成要维护的维度,枚举序列的位置,维护所有时间的前缀(max)及其贡献历史和。

    可以用吉司机线段树解决。


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #define N 200005
    #define ll long long
    int n,m;
    int a[N],lst[N];
    set<int> buc[N];
    int mx[N*4];
    ll f[N*4];
    ll tquery(int k,int l,int r,int x){
    	if (l==r)
    		return max(x,mx[k]);
    	int mid=l+r>>1;
    	if (x>mx[k<<1]) return (ll)x*(mid-l+1)+tquery(k<<1|1,mid+1,r,x);
    	return tquery(k<<1,l,mid,x)+f[k];
    }
    void build(int k,int l,int r){
    	if (l==r){
    		mx[k]=lst[l];
    		return;
    	}
    	int mid=l+r>>1;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    	mx[k]=max(mx[k<<1],mx[k<<1|1]);
    	f[k]=tquery(k<<1|1,mid+1,r,mx[k<<1]);
    }
    void modify(int x,int c,int k=1,int l=1,int r=n){
    	if (l==r){
    		mx[k]=c;
    		return;
    	}
    	int mid=l+r>>1;
    	if (x<=mid) modify(x,c,k<<1,l,mid);
    	else modify(x,c,k<<1|1,mid+1,r);
    	mx[k]=max(mx[k<<1],mx[k<<1|1]);
    	f[k]=tquery(k<<1|1,mid+1,r,mx[k<<1]);
    }
    ll ans;
    void query(int st,int en,int &x,int k=1,int l=1,int r=n){
    	if (st<=l && r<=en){
    		ans+=tquery(k,l,r,x);
    		x=max(x,mx[k]);
    		return;
    	}
    	int mid=l+r>>1;
    	if (st<=mid) query(st,en,x,k<<1,l,mid);
    	if (mid<en) query(st,en,x,k<<1|1,mid+1,r);
    }
    int main(){
    //	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	freopen("team.in","r",stdin);
    	freopen("team.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;++i){
    		scanf("%d",&a[i]);
    		if (!buc[a[i]].empty())
    			lst[i]=*buc[a[i]].rbegin();
    		buc[a[i]].insert(i);
    	}
    	build(1,1,n);
    	for (int i=1;i<=m;++i){
    		int op,x,y;
    		scanf("%d%d%d",&op,&x,&y);
    		if (op==1){
    			buc[a[x]].erase(x);
    			auto p=buc[a[x]].upper_bound(x);
    			if (p!=buc[a[x]].end()){
    				if (p==buc[a[x]].begin())
    					lst[*p]=0;
    				else{
    					auto q=p;
    					lst[*p]=*(--q);
    				}
    				modify(*p,lst[*p]);
    			}			
    			a[x]=y;
    			p=buc[y].upper_bound(x);
    			if (p!=buc[y].end()){
    				lst[*p]=x;
    				modify(*p,lst[*p]);
    			}
    			if (p==buc[y].begin())
    				lst[x]=0;
    			else
    				lst[x]=*(--p);
    			modify(x,lst[x]);
    			buc[y].insert(x);
    		}
    		else{
    			ans=0;
    			int z=x-1;
    			query(x,y,z);
    			printf("%lld
    ",(ll)(x+y)*(y-x+1)/2-ans);
    		}	
    	}
    	return 0;
    }
    
  • 相关阅读:
    使用Docker在本地搭建Hadoop分布式集群
    微博推荐 第三个map 源码
    对象
    http无状态(stateless)
    理解http的无连接
    http响应报文之首部行
    http响应报文之状态行
    http响应报文
    http请求报文之首部行
    http请求之请求数据
  • 原文地址:https://www.cnblogs.com/jz-597/p/14070633.html
Copyright © 2011-2022 走看看