【Dynamic len(set(a[L:R]))】 题解

\(solution\)

这是一道带修莫队模板题。

\(Link\)

这道题目和P1903基本上相同,只是查询的区间是 \([L,R - 1]\) , 数组的下标是 \([0,N - 1]\)

带修莫队的写法和普通莫队基本相同,只是再加一维时间轴 \(Time\) 表示现在的询问操作是否要被修改.

排序的时候相较于普通莫队还要加上一个关键字: 经历的修改次数 ,先询问的排前面。

inline bool CMP(Query a,Query b)
{
  return (a.x / block) == (b.x / block) ? (a.y / block == b.y / block ? a.pre < b.pre : a.y < b.y) : a.x < b.x;
}

之后就是套上普通莫队即可。

  • 建议块的大小调整为 $ n ^ \frac{2}{3}$ ,证明我不会,反正跑的更快。
  • 写莫队的时候设初始的 \(l\)\(r\) 分别为 \(1\)\(0\) ,设 \(l\)\(0\) 时容易 \(RE\)别问我怎么知道的

\(Code\)

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int Maxk = 2e6;
int n,m,sum,cnt_Q,cnt_s,block,now;
int a[Maxk],ans[Maxk],cnt[Maxk];
struct node{
  int past;
  int color;
}s[Maxk];//修改 
struct Query{
  int x;
  int y;
  int pre;
  int id;
}Q[Maxk];
inline int read()
{
  int x = 0,f = 0;char ch = getchar();
  while(!isdigit(ch)) f |= ch == '-',ch = getchar();
  while(isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48),ch = getchar();
  return f ? -x : x;
}
inline bool CMP(Query a,Query b)
{
  return (a.x / block) == (b.x / block) ? (a.y / block == b.y / block ? a.pre < b.pre : a.y < b.y) : a.x < b.x;
}
inline void add(int x)
{
  if(++ cnt[a[x]] == 1) sum ++;
  return;
}
inline void del(int x)
{
  if(-- cnt[a[x]] == 0) sum --;
  return;
}
void solve(int now,int i)
{
  if(s[now].past >= Q[i].x && s[now].past <= Q[i].y) {
  //只有修改在查询的区间内才会对查询的结果产生影响
    if(-- cnt[a[s[now].past]] == 0) sum --;
    if(++ cnt[s[now].color] == 1) sum ++;
  }
  swap(s[now].color ,a[s[now].past]);
  return;
}
void work()
{
  int l = 1,r = 0;now = 0;
  for(int i = 1;i <= cnt_Q;i ++) {
    int ql = Q[i].x;
    int qr = Q[i].y;
    while(l < ql) del(l ++);
    while(l > ql) add(-- l);
    while(r > qr) del(r --);
    while(r < qr) add(++ r);//模板
    while(now < Q[i].pre) solve(++ now,i); //改少了,改过去
    while(now > Q[i].pre) solve(now --,i); //改多了,改回来
    ans[Q[i].id] = sum;
  }
  for(int i = 1;i <= cnt_Q;i ++) {
    printf("%d\n",ans[i]);
  }
  return;
}
signed main()
{
  n = read(),m = read();
  for(int i = 1;i <= n;i ++) a[i] = read();
  block = pow(n,(double) 2.0 / 3.0);
  while(m --) {
    char c; cin >> c;
    if( c == 'Q') {
      Q[++ cnt_Q].x = read() + 1;
      Q[cnt_Q].y = read();
      Q[cnt_Q].pre = cnt_s;//记录最近的修改位置
      Q[cnt_Q].id = cnt_Q;//记录编号 
    }
    else {
      s[++ cnt_s].past = read() + 1;
      s[cnt_s].color = read();
    }
  }
  sort(Q + 1,Q + cnt_Q + 1,CMP);
  work();
  return 0;
}
posted @ 2021-03-03 10:49  Ti_Despairy  阅读(164)  评论(0)    收藏  举报