• 莫队与分块精简小结


    我觉得我还要补上带修莫队,树上莫队等等……(先咕着……)

    分块:引用范围广,实现简洁(注意块的边界)一般为(sqrt{n})分块。

    块中可维护很多东西,维护信息时从后往前处理。

    例题:(HNOI2010)弹飞绵羊

    #include<bits/stdc++.h>
    using namespace std;
    #define S(x) ((x)*(x))
    inline int read()
    {
        int f=1,w=0;char x=0;
        while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
        while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
        return w*f;
    }
    const int N=2e5+10;
    int n,m,Cnt,Siz;
    int K[N],Typ[N],Tim[N],End[N];
    struct Lump{int l,r;} Lum[N];
    inline void Prepare(int l,int r)
    {
    	for(int i=r;i>=l;i--)
    		if(i+K[i]>=Lum[Typ[i]].r) Tim[i]=1,End[i]=i+K[i];
    		else Tim[i]=Tim[i+K[i]]+1,End[i]=End[i+K[i]];
    }
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("A.in","r",stdin);
    #endif
    	n=read(),Siz=sqrt(n);
    	for(int i=1;i<=n;i++) K[i]=read();
    	for(int i=1;i<=n&&i+Siz-1<=n;i+=Siz) Lum[++Cnt].l=i,Lum[Cnt].r=i+Siz-1;
    	if(Lum[Cnt].r<n) Lum[++Cnt].l=Lum[Cnt-1].r+1,Lum[Cnt].r=n;Cnt=1;
    	for(int i=1;i<=n;i++) Cnt+=(i>Lum[Cnt].r),Typ[i]=Cnt;
    	Prepare(1,n);m=read();
    	while(m--)
    	{
    		int C=read(),j=read()+1,k;
    		if(C==1)
    		{
    			int ans=Tim[j],Now=End[j];
    			while(Now<=n)
    				ans+=Tim[Now],Now=End[Now];
    			printf("%d
    ",ans);
    		}
    		else k=read(),K[j]=k,Prepare(Lum[Typ[j]].l,Lum[Typ[j]].r);
    	}
    }
    

    莫队:带有分块思想的优化暴力。

    例题:(SP3267D-query)

    考虑一个优化:用两个指针移动,来计算答案,指针移动到和询问重合时记录答案。

    优化操作代码:((Sum)为不同元素个数,(Tag)为记录的桶,(Num)为元素类型)

    while(l<p[i].l) Sum-=(!(--Tag[Num[l++]]));
    while(l>p[i].l) Sum+=(!(Tag[Num[--l]]++));
    while(r<p[i].r) Sum+=(!(Tag[Num[++r]]++));
    while(r>p[i].r) Sum-=(!(--Tag[Num[r--]]));
    

    但是这样仍然会被卡死,考虑对询问排序。如果是一般的排序,显然还是会导致被卡。

    如何写(Cmp),我们可以对(1sim n)分块,如果两个区间左端点在同一个块内,按右端点排序,如不在,按左端点在的块排序。复杂度不会证……这是一个讲的较好的详解

    有一个小小的常数优化,就是分奇偶性排序,左端点在同一个奇数块中,按右端点从小到大排,在同一个偶数块中,按右端点从大到小排序,不在同一个块中按块排序。

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        int f=1,w=0;char x=0;
        while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
        while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
        return w*f;
    }
    const int N=1e6+10;
    //map<int,int> Tag;
    struct Region{int l,r,Id;} p[N];
    int n,m,Siz,Cnt,Sum,Num[N],Typ[N],ans[N],Tag[N];
    inline bool Cmp(Region x,Region y) {return (Typ[x.l]^Typ[y.l])?Typ[x.l]<Typ[y.l]:((Typ[x.l]&1)?x.r<y.r:x.r>y.r);}
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("A.in","r",stdin);
    #endif
    	n=read();Siz=sqrt(n);
    	for(int i=1;i<=n;i++) Num[i]=read(),Typ[i]=(i-1)/Siz+1;
    	int l=1,r=0;m=read();
    	for(int i=1;i<=m;i++) p[i].l=read(),p[i].r=read(),p[i].Id=i;
    	sort(p+1,p+m+1,Cmp);
    	for(int i=1;i<=m;i++)
    	{
    		while(l<p[i].l) Sum-=(!(--Tag[Num[l++]]));
    		while(l>p[i].l) Sum+=(!(Tag[Num[--l]]++));
    		while(r<p[i].r) Sum+=(!(Tag[Num[++r]]++));
    		while(r>p[i].r) Sum-=(!(--Tag[Num[r--]]));
    		ans[p[i].Id]=Sum;
    	}
    	for(int i=1;i<=m;i++) printf("%d
    ",ans[i]);
    }
    
  • 相关阅读:
    STOAdiary20110315完成的任务
    java MD5 密码加密例子
    STOAdiary20110316完成的任务
    个人实习总结
    STOAdiary20110317完成的任务
    Android 操作XML的几种方式
    Ubuntu 桌面图标不见,鼠标右键的问题
    20110329日记
    MySql 中文问题的处理
    20110312wmh日记
  • 原文地址:https://www.cnblogs.com/wo-shi-zhen-de-cai/p/11710199.html
Copyright © 2020-2023  润新知