zoukankan      html  css  js  c++  java
  • 2120: 数颜色(带修莫队)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2120

    2120: 数颜色

    Time Limit: 6 Sec  Memory Limit: 259 MB
    Submit: 10514  Solved: 4398
    [Submit][Status][Discuss]

    Description

    墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

    Input

    第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

    Output

    对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

    Sample Input

    6 5
    1 2 3 4 5 5
    Q 1 4
    Q 2 6
    R 1 2
    Q 1 4
    Q 2 6

    Sample Output

    4
    4
    3
    4

    HINT

    对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。


    2016.3.2新加数据两组by Nano_Ape

    ·述大意:

           多个区间询问,询问[l,r]中颜色的种类数。可以单点修改颜色。

    ·分析:

    莫队可以修改?那不是爆炸了吗。

    这类爆炸的问题被称为带修莫队(可持久化莫队)。

    按照美妙类比思想,可以引入一个“修改时间”,表示当前询问是发生在前Time个修改操作后的。也就是说,在进行莫队算法时,看看当前的询问和时间指针(第三个指针,别忘了l,r)是否相符,然后进行时光倒流或者时光推移操作来保证答案正确性。

    ·Sort的构造。仅靠原来的sort关键字会使得枚举每个询问都可能因为时间指针移动的缘故要移动n次,总共就n2次,那还不如写暴力。

    ·为了防止这样的事情发生,再加入第三关键字Tim:

    image

    ·如何理解时间复杂度?

    首先,R和Tim的关系就像L和R的关系一样:只有在前者处于同块时,后者才会得到排序的恩赐,否则sort会去满足前者,使得后者开始乱跳。

    依旧像上文那样:枚举m个答案,就一个m了。设分块大小为unit。

    分类讨论:

    ①对于l指针,依旧是O(unit*n)

    ②对于r指针,依旧是O(n*n/unit)

    ③对于T指针(即Time):

        类比r时间复杂度的计算。我们要寻找有多少个单调段(一个单调段下来最多移动n次)。上文提到,当且仅当两个询问l在同块,r也在同块时,才会对可怜的Tim进行排序。局势明朗。对于每一个l的块,里面r最坏情况下占据了所有的块,所以最坏情况下:有n/unit个l的块,每个l的块中会有n/unit个r的块,此时,在一个r块里,就会出现有序的Tim。所以Tim的单调段个数为:(n/unit)*(n/unit)。每个单调段最多移动n次。

    所以:O((n/unit)2*n)

    三个指针汇总:O(unit*n+n2/unit+(n/unit)2*n)

    image

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int maxn=1000000+50;
    int block;
    int a[maxn],b[maxn],ans1[maxn];
    int ans=0;
    struct Q
    {
        int x,y,num,tim;
    }q[maxn];
    struct U
    {
        int x,y;
    }tw[maxn];
    bool cmp(const Q a,const Q b)
    {
        if(a.x/block==b.x/block)
        {
            if(a.y/block==b.y/block) return a.tim<b.tim;
            return a.y/block<b.y/block;
        }
        return a.x/block<b.x/block;
    }
    void solve(int n,int add)
    {
        b[a[n]]+=add;
        if(b[a[n]]==1&&add==1) ans++;
        else if(b[a[n]]==0&&add==-1) ans--;
    }
    void time_charge(int n,int t)
    {
        if(q[n].x<=tw[t].x&&tw[t].x<=q[n].y)
        {
            b[a[tw[t].x]]--;
            if(b[a[tw[t].x]]==0) ans--;
            b[tw[t].y]++;
            if(b[tw[t].y]==1) ans++;
        }
        swap(tw[t].y,a[tw[t].x]);
    }
    int main()
    {
        int N,M,t=0,p1=0,p2=0;
        char c[10];
        scanf("%d%d",&N,&M);
        block=pow(N,0.66666);
        for(int i=1;i<=N;i++) scanf("%d",&a[i]);
        for(int i=0;i<M;i++)
        {
            scanf("%s",c);
            if(c[0]=='Q')
            {
                scanf("%d%d",&q[p1].x,&q[p1].y);
                q[p1].num=p1;
                q[p1].tim=t;
                p1++;
            }
            else
            {
                t++;
                scanf("%d%d",&tw[t].x,&tw[t].y);
            }
    
        }
        sort(q,q+p1,cmp);
        int L=1,R=0,T=0;
        for(int i=0;i<p1;i++)
        {
            while(R<q[i].y)//往右走
            {
                solve(R+1,1);
                R++;
            }
            while(R>q[i].y)
            {
                solve(R,-1);
                R--;
            }
            while(L<q[i].x)
            {
                solve(L,-1);
                L++;
            }
            while(L>q[i].x)
            {
                solve(L-1,1);
                L--;
            }
            while(T<q[i].tim)
            {
                time_charge(i,T+1);
                T++;
            }
            while(T>q[i].tim)
            {
                time_charge(i,T);
                T--;
            }
            ans1[q[i].num]=ans;
        }
        for(int i=0;i<p1;i++) printf("%d
    ",ans1[i]);
        return 0;
    }
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    八数码难题 (codevs 1225)题解
    小木棍 (codevs 3498)题解
    sliding windows (poj 2823) 题解
    集合删数 (vijos 1545) 题解
    合并果子 (codevs 1063) 题解
    等价表达式 (codevs 1107)题解
    生理周期 (poj 1006) 题解
    区间 (vijos 1439) 题解
    区间覆盖问题 题解
    种树 (codevs 1653) 题解
  • 原文地址:https://www.cnblogs.com/caijiaming/p/10846914.html
Copyright © 2011-2022 走看看