分块 公主的朋友

  

问题 B: 公主的朋友

时间限制: 1 Sec  内存限制: 256 MB

题目描述

由于 Wulala 在上个问题中的精彩表现,公主认为 Wulala 是一个很棒的人,就把 Wulala 留在了 X 国。这时正好公主的一位传教士朋友来拜访公主,于是想找 wulala 帮忙X 国如同一条直线,其中有 n 个城市,从东向西分别编号为 1~n。而他的国家中有 m 种宗教,每个城市一定会有一种信仰的宗教。

有时候有些城市为了获得更多的认可,会派出信仰本城市宗教的传教士前往其他国家。X 国

的传教士都十分厉害,只要是他途经的地方都会改信他所传播的宗教。

传教士们在路上碰到自己宗教的城市自然就不用传教了,可以停下来看看里番啥的,所以每

一个传教士在旅行前都会计算自己可以在多少城市停下来(不包括起始的城市)。

而传教士们都是文科僧,数学是很差的,所以他希望 Wulala 能帮他计算。可 Wulala 数学也不好,但他又不想在公主面前丢脸,你能帮帮他吗?

输入

第一行两个整数 n,m

第二行 n 个整数第 i 个整数代表第 i 各城市信仰的宗教

第三行一个整数 T 代表传教士的个数

接下来 T 行每行两个整数 x,y 代表 x 城向 y 城派遣了一个传教士(保证 x < y)

输出

输出 T 行,第 i 行代表第 i 个传教士询问的答案

样例输入

2 21 221 21 2

样例输出

01

提示

对于 30%的数据 n <= 100000, m <= 10, T <= 100

对于 60%的数据 n <= 100000, m <= 10, T <= 100000

对于 100%的数据 n <= 100000, m <= 300, T <= 100000

   可以用线段树,但分块很好想啊。。联考时又AC了一道。。

   比普通分块,我脑补出了一种分块延迟标记。指这个块如果被某个zz传教士横跨了过去,就是说这个块全变成了某一个宗教,打上个标记,记录这个块变成了某个宗教。如果这个块又被整个遍历,就不用把延迟下传。而如果这个块被当做散点遍历了,就要把标记下传,更新。

   

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define N 100000
using namespace std;
int read()
{
    int sum=0,f=1;char x=getchar();
    while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
    while(x>='0'&&x<='9'){sum=sum*10+x-'0';x=getchar();}
    return sum*f;
}
int n,m,a[N+5],kuai[N+5],h,t,v[N+5],s[2000][305];
int get(int l,int r)
{
    if(v[kuai[l-1]])a[l-1]=v[kuai[l-1]];
    int f=a[l-1],sum=0;
    if(kuai[l]==kuai[r])
    {
        if(v[kuai[l]]==f)
            return r-l+1;
        else
        {
            if(v[kuai[l]]!=0)
               for(int i=(kuai[l]-1)*h+1;i<=min(n,kuai[l]*h);i++)a[i]=v[kuai[l]];
            v[kuai[l]]=0;
            for(int i=l;i<=r;i++)
               if(a[i]!=f) 
               {
                   s[kuai[l]][a[i]]--;
                   s[kuai[l]][f]++;
                   a[i]=f;
               }
               else sum++;
            return sum;
        }
    }
    else
    {
        if(v[kuai[l]]==f)
           sum+=kuai[l]*h-l+1;
        else
        {
            if(v[kuai[l]]!=0)
               for(int i=(kuai[l]-1)*h+1;i<=kuai[l]*h;i++)a[i]=v[kuai[l]];
            v[kuai[l]]=0;               
            for(int i=l;i<=kuai[l]*h;i++)  
               if(a[i]!=f) 
               {
                   s[kuai[l]][a[i]]--;
                   s[kuai[l]][f]++;
                   a[i]=f;
               }
               else sum++;
        }
        if(v[kuai[r]]==f)
            sum+=r-(kuai[r]-1)*h;
        else
        {
            if(v[kuai[r]]!=0)
               for(int i=(kuai[r]-1)*h+1;i<=min(n,kuai[r]*h);i++)a[i]=v[kuai[r]];
            v[kuai[r]]=0;
            for(int i=(kuai[r]-1)*h+1;i<=r;i++)  
               if(a[i]!=f) 
               {
                   s[kuai[r]][a[i]]--;
                   s[kuai[r]][f]++;
                   a[i]=f;
               }
               else sum++;
        }
        for(int i=kuai[l]+1;i<kuai[r];i++)
            if(v[i]==f)
                sum+=h;
            else
            {
                sum+=s[i][f];
                v[i]=f;
                for(int j=1;j<=m;j++)s[i][j]=0;  
                s[i][f]=h;
            }
        return sum;
    }
    return sum;
}
int main()
{
    n=read();m=read();h=sqrt(n);if(h>70)h=70;
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        kuai[i]=(i-1)/h+1;
        s[kuai[i]][a[i]]++;
    }
    t=read();
    int l,r,sum=0;
    for(int i=1;i<=t;i++)
    {
        l=read();
        r=read();
        if(l==r){printf("0\n");continue;}
        sum=get(l+1,r);
        printf("%d\n",sum);
    }

posted @ 2017-10-06 20:19  Hzoi_QTY  阅读(146)  评论(0编辑  收藏  举报