AC日记——数颜色 bzoj 2120

2120

 

思路:

  带修改的莫队;

  对于离线排序询问的算法,如何修改呢?

  每个询问添加一个修改标记;

  表示当前询问在第几个修改之后;

  然后把修改标记作为第三关键字来排序;

  每次更新端点,先更新时间;

  块的大小为n的2/3次方;

 

来,上代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define maxn 100050

struct QueryType {
    int l,r,t,id;
};
struct QueryType qu[maxn];

struct ChangeType {
    int to,x,h;
};
struct ChangeType cha[maxn];

int n,m,size=440,tot,num,ai[maxn],bel[maxn],ti[maxn*10],ans[maxn];
int now;

bool if_[maxn];

inline void in(int &now)
{
    char Cget=getchar();now=0;
    while(Cget>'9'||Cget<'0') Cget=getchar();
    while(Cget>='0'&&Cget<='9')
    {
        now=now*10+Cget-'0';
        Cget=getchar();
    }
}

bool cmp(QueryType aa,QueryType bb)
{
    if(bel[aa.l]==bel[bb.l])
    {
        if(bel[aa.r]==bel[bb.r]) return aa.t<bb.t;
        else return aa.r<bb.r;
    }
    else return aa.l<bb.l;
}

inline void change(int x)
{
    if(if_[cha[x].to])
    {
        ti[ai[cha[x].to]]--;
        if(!ti[ai[cha[x].to]]) now--;
    }
    cha[x].h=ai[cha[x].to];
    ai[cha[x].to]=cha[x].x;
    if(if_[cha[x].to])
    {
        if(!ti[ai[cha[x].to]]) now++;
        ti[ai[cha[x].to]]++;
    }
}

inline void unchange(int x)
{
    if(if_[cha[x].to])
    {
        ti[ai[cha[x].to]]--;
        if(!ti[ai[cha[x].to]]) now--;
    }
    ai[cha[x].to]=cha[x].h;
    if(if_[cha[x].to])
    {
        if(!ti[ai[cha[x].to]]) now++;
        ti[ai[cha[x].to]]++;
    }
}

inline void updata(int to,int x)
{
    int pos=ti[ai[to]];
    ti[ai[to]]+=x;
    if(ti[ai[to]]==0&&pos==1) now--;
    if(ti[ai[to]]==1&&pos==0) now++;
    if(x==1) if_[to]=true;
    else if_[to]=false;
}

int main()
{
    in(n),in(m);char ch[4];int l,r,t;
    for(int i=1;i<=n;i++) in(ai[i]),bel[i]=(i-1)/size;
    for(int i=1;i<=m;i++)
    {
        scanf("%s",ch);in(l),in(r);
        if(ch[0]=='Q') qu[++tot].l=l,qu[tot].r=r,qu[tot].t=num,qu[tot].id=tot;
        else cha[++num].to=l,cha[num].x=r;
    }
    sort(qu+1,qu+tot+1,cmp),l=1,r=0,t=0,now=0;
    for(int no=1;no<=tot;no++)
    {
        while(t<qu[no].t) change(++t);
        while(t>qu[no].t) unchange(t--);
        while(r<qu[no].r) updata(++r,1);
        while(r>qu[no].r) updata(r--,-1);
        while(l<qu[no].l) updata(l++,-1);
        while(l>qu[no].l) updata(--l,1);
        ans[qu[no].id]=now;
    }
    for(int i=1;i<=tot;i++) printf("%d\n",ans[i]);
    fclose(stdin),fclose(stdout);
    return 0;
}

 

转载于:https://www.cnblogs.com/IUUUUUUUskyyy/p/6762736.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值