zoukankan      html  css  js  c++  java
  • [国家集训队]数颜色 / 维护队列(莫队)

    嘟嘟嘟


    带修改莫队。
    以前学过没懂,今天又学了一遍竟然会了。


    其实他跟普通莫队相比,就多了一维:时间。
    首先也是都离线。
    然后对于每一个询问,记录这几个信息:
    1.左右端点。
    2.询问编号。(为了输出答案)
    3.时间编号。
    然后把询问排序。这个和无修改莫队一样,第一关键字是左端点所在块,第二关键字是右端点所在块。
    对于每一个修改,记录这几个信息:
    1.时间编号。
    2.修改位置。
    3.修改后的值。


    然后就是根据询问,左右端点加加减减了。但因为有修改,所以每一次移动端点前先要把时间调到当前询问的时间上。
    如果询问时间比当前时间晚,就把这期间的修改全做了,并且如果有的修改在当前询问区间内,就看看能否对答案产生贡献;如果询问时间比当前时间早,那么我们就要“时光倒流”,把这期间改过的点都改回来,并且还要看看对答案有没有贡献。
    因此,需要记录每一个修改前该位置的数,好方便改回来。
    做完这一步之后,当前的时间就是询问时间了,然后就是正常的莫队操作了。


    总而言之,带修改莫队也挺暴力的。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define rg register
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 5e4 + 5;
    const int maxm = 1e6 + 5;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, m, a[maxn];
    char c[2];
    const int S = 464;
    #define bel(x) (((x) - 1) / S + 1)
    struct Node
    {
      int id, tim, L, R;
      bool operator < (const Node& oth)const
      {
        if(bel(L) != bel(oth.L)) return L < oth.L;
        if(bel(R) != bel(oth.R)) return R < oth.R;
        return id < oth.id;
      }
    }q[maxn];
    int l = 1, r = 0, cntQ = 0, cur = 0;
    int cntC = 0, tim[maxn], pos[maxn], val[maxn], pre[maxn];
    int cnt = 0, tot[maxm], ans[maxn];
    
    void change_add(int cur)
    {
      if(pos[cur] >= l && pos[cur] <= r) if(!--tot[a[pos[cur]]]) cnt--;  //把原来的贡献减去
      pre[cur] = a[pos[cur]];
      a[pos[cur]] = val[cur];
      if(pos[cur] >= l && pos[cur] <= r) if(!tot[a[pos[cur]]]++) cnt++;  //加上改完后的贡献
    }
    void change_del(int cur)
    {
      if(pos[cur] >= l && pos[cur] <= r) if(!--tot[a[pos[cur]]]) cnt--;
      a[pos[cur]] = pre[cur];
      if(pos[cur] >= l && pos[cur] <= r) if(!tot[a[pos[cur]]]++) cnt++;
    }
    void change(int now)  //把时间调到当前询问上
    {
      while(cur < cntC && tim[cur + 1] <= now) change_add(++cur);
      while(cur && tim[cur] > now) change_del(cur--);
    }
    
    void add(int now)
    {
      if(!tot[a[now]]++) cnt++;
    }
    void del(int now)
    {
      if(!--tot[a[now]]) cnt--;
    }
    
    int main()
    {
      n = read(); m = read();
      for(int i = 1; i <= n; ++i) a[i] = read();
      for(int i = 1; i <= m; ++i)
        {
          scanf("%s", c);
          if(c[0] == 'Q')
    	{
    	  cntQ++;
    	  q[cntQ].id = cntQ; q[cntQ].tim = i;
    	  q[cntQ].L = read(); q[cntQ].R = read();
    	}
          else tim[++cntC] = i, pos[cntC] = read(), val[cntC] = read();  
        }
      sort(q + 1, q + cntQ + 1);
      for(int i = 1; i <= cntQ; ++i)
        {
          change(q[i].tim);
          while(l > q[i].L) add(--l);
          while(l < q[i].L) del(l++);
          while(r < q[i].R) add(++r);
          while(r > q[i].R) del(r--);
          ans[q[i].id] = cnt;
        }
      for(int i = 1; i <= cntQ; ++i) write(ans[i]), enter;
      return 0;
    }
    
  • 相关阅读:
    ASP.NET Web API涉及到的上下文
    .NET Core 和 ASP.NET 5 RC1 发布
    通过NameValuePairsValueProvider对象来获取指定前缀的Key
    ASP.NET Web API获取Model元数据
    功放AUX接口解析
    安全协议:SSL、TSL、SSH概述
    从自签名证书导出pfx和cer证书
    windows下使用makecert命令生成自签名证书
    低音炮四种典型的接线方法
    音箱灵敏度
  • 原文地址:https://www.cnblogs.com/mrclr/p/10077117.html
Copyright © 2011-2022 走看看