zoukankan      html  css  js  c++  java
  • 【笔记篇】莫队算法(二)

    嗯,我们已经能通过莫队处理查询线性结构上的查询了。
    但是,这怎么能够呢= =
    现在的题里面基本上都要牵扯上修改操作啊。。。
    比如动不动就会出一个“把节点x的值修改为y的操作”。。。

    而我们知道,莫队是离线算法,要把所有操作都读进来,那么修改操作就会对后面的查询操作造成影响。。
    如何消除这种影响呢?
    我们可以再加一个维度——时间。
    我们对于每一个查询操作,记录一个时间T,表示之前进行过T次修改了。
    然后排序的时候,按左端点的块编号为第一关键字,右端点的块编号为第二关键字,时间为第三关键字排序即可。

    bool cmp(const query &a,const query &b){
    	if(a.l/blk==b.l/blk){
    		if(a.r/blk==b.r/blk) return a.ti<b.ti;
    		return a.r<b.r;
    	}
    	return a.l<b.l;
    }
    

    对于每一个修改,我们只需要记录每个修改的修改前和修改后的信息,然后像移动L,R一样移动T即可。
    定义一个修改的结构体,像这样:

    struct modify{
    	int pos,pre,now; //这次修改将pos位置从pre改为now
    };
    

    我们只需要写一个操作:

    void change(int l,int r,int x,int c) //当前区间为[l,r],把x点更改为c
    {
    	//TODO:这里维护信息
    	if(l<=x&&x<=r)
    	{
    		//维护改动
    	}
    	//修改该点 比如col[x]=c;
    }
    

    然后我们在solve()函数中扫的时候,扫时间的话就

    int T=q[i].ti;
    while(ti<T) ++ti,change(l,r,t[T].pos,t[T].now); //没改的时候要改成改后的颜色
    while(ti>T) change(l,r,t[T].pos,t[T].pre),ti--; //改过了的话要改回改前的颜色
    

    经检验,对于带修改的莫队算法,分块大小分到(n^frac{2}{3}) 应该是最优的,可以证明,最坏时间复杂度为(O(n^frac{5}{3}))(强行不到(n^2)系列。。。)

    下面就贴一道例题和代码吧= =
    例题:bzoj2120 http://www.lydsy.com/JudgeOnline/problem.php?id=2120

    代码:

    /**************************************************************
        Problem: 2120
        User: zyan
        Language: C++
        Result: Accepted
        Time:832 ms
        Memory:6840 kb
    ****************************************************************/
     
    #include <cmath>
    #include <vector>
    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N=50505;
    const int C=1010101;
    int n,m,blk,opt,qid,tid;
    int col[N],last[N],ans[N],ex[N],cur[C];
    struct query{
        int l,r,id,ti;
    }q[50505];
    bool cmp(const query &a,const query &b){
        if(a.l/blk==b.l/blk){
            if(a.r/blk==b.r/blk) return a.ti<b.ti;
            return a.r<b.r;
        }
        return a.l<b.l;
    }
    struct modify{
        int p,pre,cur;
    }t[1010];
     
    inline int gnum(){
        int a=0;char c=getchar();bool f=0;
        for(;(c<'0'||c>'9')&&c!='-'&&c!='Q'&&c!='R';c=getchar());
        if(c=='Q')return -1; if(c=='R')return -2; 
        if(c=='-') c=getchar(),f=1;
        for(;c>='0'&&c<='9';c=getchar()) a=(a<<1)+(a<<3)+c-'0';
        if(f) return -a; return a;
    }
     
    void change(int l,int r,int x,int c,int &res){
        if(l<=x&&x<=r){
            cur[col[x]]--; if(!cur[col[x]]) res--;
            col[x]=c; if(!cur[col[x]]) res++; cur[col[x]]++;
        }
        else col[x]=c;
    }
     
    void fix(int p,int &res){
        if(ex[p]){
            cur[col[p]]--;
            if(!cur[col[p]]) res--;
        }
        else{
            if(!cur[col[p]]) res++;
            cur[col[p]]++;
        }
        ex[p]^=1;
    }
     
    void solve(){
        sort(q+1,q+qid+1,cmp);
        int ti=0,l=q[1].l,r=q[1].l-1,res=0;
        for(int i=1;i<=qid;i++){
            int L=q[i].l,R=q[i].r,T=q[i].ti;
            while(ti>T) change(l,r,t[ti].p,t[ti].pre,res),ti--;
            while(ti<T) ti++,change(l,r,t[ti].p,t[ti].cur,res);
            while(l<L) fix(l++,res);
            while(l>L) fix(--l,res);
            while(r>R) fix(r--,res);
            while(r<R) fix(++r,res);
            ans[q[i].id]=res;
        }
    }
      
    int main(){
        n=gnum(),m=gnum(); blk=sqrt(n);
         
        for(int i=1;i<=n;i++) last[i]=col[i]=gnum();
         
        for(int i=1;i<=m;i++){ opt=gnum();
            if(opt==-1) {int L=gnum(),R=gnum(); q[++qid].l=L,q[qid].r=R,q[qid].id=qid,q[qid].ti=tid;}
            else{int x=gnum(),p=gnum(); t[++tid].p=x; t[tid].pre=last[x]; t[tid].cur=p; last[x]=p;} //这里改的时候一定要记一下last表示最近一次更改后变成了什么颜色
        } solve();
        for(int i=1;i<=qid;i++) printf("%d
    ",ans[i]);
    }
    

    嗯 就是这样啦~

  • 相关阅读:
    WPF快速指导10:WPF中的事件及冒泡事件和隧道事件(预览事件)的区别
    改善C#程序的建议1:非用ICloneable不可的理由
    WPF快速指导5:验证
    改善C#程序的建议4:C#中标准Dispose模式的实现
    我所入选的微软技术社区电子报
    C#中new, override, virtual的具体用法
    C#中FCL迭代器模式的一点问题
    WPF快速指导3:数据绑定
    WPF快速指导2:模板
    C#高效编程话题集2(每期10话题)
  • 原文地址:https://www.cnblogs.com/enzymii/p/8412192.html
Copyright © 2011-2022 走看看