HYSBZ - 2120:数颜色 (带修改操作的莫队算法)


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


题目大意:

中文题面,不多解释了。


解题思路:

首先可以看出此题如果不带修改操作的话其实是一个比较裸的莫队算法的题目。但是这其中有修改操作,所以要加一些变化,本来看到题面上说修改操作最多1000次,自己想了一种做法就是将每次修改操作前的查询操作离线并且计算答案记录,后来发现tle了。。然后就gg了,个人是真的没啥办法了。到网上看了大神的思路,真的是膜拜,具体就是将修改操作也加入莫队的过程,每次计算贡献,具体说不清楚,看代码自行理解吧,以下为代码,


#include <bits/stdc++.h>
#define rank ra
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
using namespace std;
typedef long long ll;
const int N=10005;
int n,m,step,cnt,sz,sk;
  
struct node     //记录询问
{
    int l,r,id,gk;
}qu[N];
struct Node     //记录修改前颜色和修改后颜色以及修改位置
{
    int pos,now,past;
}ch[N];
int L,R,a[N],pos[N],p,q,g1,g2,ka[N];    //注意a和ka数组 ka数组为辅助得到修改操作的now past
int ans[N],res;
char s;
int vis[1000005];   //这里用map会t
bool cmp(node p,node q)     //分块排序
{
    if(pos[p.l]==pos[q.l])
        return p.r<q.r;
    return p.l<q.l;
}
void del(int k)     //删除当前点对答案的贡献
{
    vis[k]--;
    if(vis[k]==0)
        res--;
}
void add(int k)     //同上
{
    vis[k]++;
    if(vis[k]==1)
        res++;
}
void update(int x,int l,int r,int flag)     //更新修改操作对答案的影响
{
    if(x<=0||x>g2) return;
    int pos=ch[x].pos;
    if(pos>=l&&pos<=r)
        del(a[pos]);
    if(flag>0)
        a[pos]=ch[x].now;
    if(flag<0)      //注意千万别写成else 血的教训
        a[pos]=ch[x].past;
    if(pos>=l&&pos<=r)
        add(a[pos]);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        sz=sqrt(n);
        memset(vis,0,sizeof vis);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            ka[i]=a[i];
            pos[i]=i/sz;
        }
        g1=0,g2=0;      //记录查询的个数和修改的个数
        for(int i=1;i<=m;i++)
        {
            scanf(" %c%d%d",&s,&p,&q);
            if(s=='Q')
            {
                qu[++g1].l=p;qu[g1].r=q;
                qu[g1].gk=g2;
                qu[g1].id=g1;
            }
            if(s=='R')
            {
                ch[++g2].now=q;ch[g2].past=ka[p];
                ch[g2].pos=p;
                ka[p]=q;
            }
        }
        L=1,R=0,res=0,cnt=0;
        sort(qu+1,qu+1+g1,cmp);
        for(int i=1;i<=g1;i++)       //莫队算法
        {
            while(L<qu[i].l)
            {
                del(a[L]);
                L++;
            }
            while(L>qu[i].l)
            {
                L--;
                add(a[L]);
            }
            while(R<qu[i].r)
            {
                R++;
                add(a[R]);
            }
            while(R>qu[i].r)
            {
                del(a[R]);
                R--;
            }
            while(cnt<qu[i].gk)     //这里更新修改操作对答案的影响
                update(++cnt,L,R,1);
            while(cnt>qu[i].gk)
                update(cnt--,L,R,-1);
            ans[qu[i].id]=res;
        }
        for(int i=1;i<=g1;i++)
            printf("%d\n",ans[i]);
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值