分块模板+模板题

嗯…直接贴板子了,(注释写了点)..

模板

#include
using namespace std;
const int maxn=1e5+10;
int a[maxn],belong[maxn],L[1010],R[1010],block,num;//a数组存取原始数据,belong数组表示每个数属于哪一块方便调用,L和R表示各块左右端点,block各块大小,num块数量
void change(int l,int r,int add)//修改,视情况而定
{
    //略..(可见下面模板题)
}
int query(int l,int r)//查询,同上
{
    //略..
}
void build(int n)//建立各块(各个分块这个操作大致一样)
{
    block=sqrt(n);//大小
    num=n/block;if(n%block)num++;//如果不整除显然数量加个1
    for(int i=1;i<=num;i++)
        L[i]=(i-1)*block+1,R[i]=i*block;//左右端点
    R[num]=n;   //最后一个右端点一定是结尾
    for(int i=1;i<=n;i++)
        belong[i]=(i-1)/block+1;    //belong数组
    //初始状态维护......(省略)
}
int main()//读入
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(n);
    //询问......(省略)
}

模板题–洛谷P1903 数颜色

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:

1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。

2、 R P Col 把第P支画笔替换为颜色Col。

为了满足墨墨的要求,你知道你需要干什么了吗?

输入输出格式

输入格式:
第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。

第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。

第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

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

基本是裸的,不过数据要稍微离散下,再加个bitset加速(离散还不怎么会…)
代码(最慢点196ms)

#include
using namespace std;
const int maxn=1e5+7;
int a[maxn],t[maxn],belong[maxn],num,L[1010],R[1010],mp[1000010],cnt=0,block;
bitset<11010>bst[4010],ans;bool vis[11010];
void lisan(int n)//离散
{
    int m;
    for(int i=1;i<=n;i++)
        t[i]=a[i];
    sort(t+1,t+n+1);
    m=unique(t+1,t+n+1)-t-1;
    for(int i=1;i<=n;i++)
        mp[a[i]]=a[i]=lower_bound(t+1,t+1+m,a[i])-t;        
}
void build(int n)
{
    block=sqrt(n);num=n/block;
    if(n%block)num++;
    for(int i=1;i<=num;i++)
        L[i]=(i-1)*block+1,R[i]=i*block;
    R[num]=n;
    for(int i=1;i<=n;i++)
        belong[i]=(i-1)/block+1;
    for(int i=1;i<=num;i++)//初始化
    {   
        bst[i].reset();
        for(int j=L[i];j<=R[i];j++)
            bst[i].set(a[j]);   
    }   
}
int query(int l,int r)
{
    if(belong[l]==belong[r])//注意!!这个情况要特判!基本所有分块的查询都是
    {
        int res=0;
        memset(vis,0,sizeof vis);
        for(int i=l;i<=r;i++)
        {if(!vis[a[i]])vis[a[i]]=1,res++;}
        return res;
    }
    ans.reset();
    for(int i=l;i<=R[belong[l]];i++)
        ans.set(a[i]);
    for(int i=belong[l]+1;i//暴力搞
        ans|=bst[i];
    for(int i=L[belong[r]];i<=r;i++)
        ans.set(a[i]);
    return ans.count();     
}
void change(int pos,int to)//同上暴力
{   
        if(mp[to]==-1)++cnt,mp[to]=cnt+10000;
        a[pos]=mp[to];
        bst[belong[pos]].reset();
        for(int i=L[belong[pos]];i<=R[belong[pos]];i++)
            bst[belong[pos]].set(a[i]);
        return;
}
int main()
{
    int n,m,l,r;char op;
    memset(mp,-1,sizeof mp);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    lisan(n);
    build(n);
    while(m--)
    {
        scanf(" %c",&op);
        scanf("%d%d",&l,&r);
        if(op=='Q')printf("%d\n",query(l,r));
        else change(l,r);
    }
    return 0;
}

你可能感兴趣的:(训练集)