zoukankan      html  css  js  c++  java
  • [模板] 带修莫队

    一、题目

    点此看题

    其实是一道带修莫队的模板题啊。

    二、解法

    普通莫对其实是一个二维的信息 ((l,r)),既然要支持修改,我们添加一个信息表示这个询问用到的修改是 ([1,t]),那么我们可以用一个三维信息来表示一个询问 ((l,r,t))

    排序的方法是这样的:先判断 (l) 在不在一个块内,不在一个块内就直接排;再判断 (r) 在不在一个块内,不在一个块内就直接排;最后按 (t) 从小到大排序。排完序之后直接按普通莫队的做法做就行,实现代码如下:

    bool operator < (const node &b) const
    {
    	if(pos[l]!=pos[b.l]) return l<b.l;
    	if(pos[r]!=pos[b.r]) return r<b.r;
    	return t<b.t;
    }
    

    本文的重点是证明待修莫对的时间复杂度,时间消耗主要分成三个部分,设块长为 (a)

    • (t) 轴的移动时间复杂度,因为 ((l,r)) 的组合只有 (frac{n^2}{a^2}) 种,每一种的时间消耗为 (t),总时间复杂度 (O(frac{n^2}{a^2}t))
    • 如果 (l,r) 所在块相同那么 (l,r) 的移动复杂度为 (O(na)),可以看做每一个询问都在块里面乱动。
    • (l) 从一个块到另一个块时 (r) 移动的时间复杂度为 (O(frac{n^2}{a})),单次是 (O(n)) 的乘上的块的个数。

    (a) 一般取 (O(n^{frac{5}{3}})),我习惯于把块长设为定值。还有这道板题有一个细节,就是我们要在修改处记录修改之前的权值,这样就方便回退了。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int M = 200005;
    const int sq = 2412;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,ans,ln,l,r,t,res[M],cnt[5*M];
    int a[M],b[M],c[M],d[M],pos[M];char s[M];
    struct node
    {
    	int l,r,t,id;
    	bool operator < (const node &b) const
    	{
    		if(pos[l]!=pos[b.l]) return l<b.l;
    		if(pos[r]!=pos[b.r]) return r<b.r;
    		return t<b.t;
    	}
    }q[M];
    void add(int x)
    {
    	if(cnt[x]==0) ans++;
    	cnt[x]++;
    }
    void del(int x)
    {
    	cnt[x]--;
    	if(cnt[x]==0) ans--;
    }
    signed main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read();
    	for(int i=1;i<=n;i++)
    		pos[i]=(i-1)/sq+1;
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%s",s);
    		int l=read(),r=read();
    		if(s[0]=='Q') q[++ln]=node{l,r,k,ln};
    		else k++,b[k]=l,c[k]=r;
    	}
    	sort(q+1,q+1+ln);
    	l=1;r=0;t=0;
    	for(int i=1;i<=ln;i++)
    	{
    		int L=q[i].l,R=q[i].r,T=q[i].t;
    		while(L<l) add(a[--l]);
    		while(L>l) del(a[l++]);
    		while(R>r) add(a[++r]);
    		while(R<r) del(a[r--]);
    		while(t<T)//增加t这个修改 
    		{
    			t++;
    			if(l<=b[t] && b[t]<=r) del(a[b[t]]);
    			d[t]=a[b[t]];//记录下修改之前的信息 
    			a[b[t]]=c[t];
    			if(l<=b[t] && b[t]<=r) add(a[b[t]]);
    		}
    		while(t>T)//回撤t这个修改
    		{
    			if(l<=b[t] && b[t]<=r) del(a[b[t]]);
    			a[b[t]]=d[t];
    			if(l<=b[t] && b[t]<=r) add(a[b[t]]);
    			t--;
    		}
    		res[q[i].id]=ans;
    	}
    	for(int i=1;i<=ln;i++)
    		printf("%d
    ",res[i]);
    }
    
  • 相关阅读:
    Django框架----路由系统(详细)
    Django框架----路由系统、视图和模板(简单介绍)
    Django框架----模板继承和静态文件配置
    Django框架----模板语法
    毕昇杯之无线通信模块
    新版本ubuntu13.10软件安装
    毕昇杯总结1
    调试程序的方法总结
    新年,新气象
    基于51,人体红外感应和RC522的门禁系统
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14556140.html
Copyright © 2011-2022 走看看