• 【国家集训队】数颜色——带修改莫队


    带修改的莫队,还没做过的莫队建议先做HH的项链(板子题)

    这里多了一个修改,首先我们要相信一个真理:暴力出奇迹

    莫队就是相当与对暴力的一个优化,

    于是对于每个询问,我们标记它的时间(也就是前面有几个修改)

    然后像普通莫队一样做,如果时间不符合,那就暴力修改or暴力撤销

    比如说我们用now记录现在的X(统计到的颜色个数)是建立在哪次修改后的基础上的(即时间)

    那么我们用数组存下了每个修改,并且用last存下某次修改前它要修改的那个空里面原本存的颜色

    这样有点绕口,我们举个栗子:

    比如原数列: 1 3 7 4 6

    现在有第二次修改3 5(把第3个修改为5)

    那么last[2]=7(当前数)

    然后修改为: 1 3 5 4 6

    这就是我们暴力向后修改的过程

    如果是撤销,那就相当于是把第i次修改的位置改为last[i]即可

    然后为了处理方便,我们先移动区间,最后修改颜色到目标时间

    修改时注意,如果要修改的这个位置在区间内(这也是先处理区间的原因),那么就更新ans,

    否则直接修改

    至于排序,,,大概是玄学复杂度吧,具体证明可以参见:

    https://www.cnblogs.com/Paul-Guderian/p/6933799.html

    --------------2018.10.11--------------优化了代码格式

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define Ri register int
      4 #define AC 10500
      5 #define D printf("line in %d
    ",i);
      6 int n, m, block, tot, cnt, L, R, now, ll, rr, tt;
      7 int color[AC], s[AC], ans[AC], have[AC], X, last[AC];
      8 struct node{
      9     int x, w;    
     10 }T[AC];
     11 struct node{
     12     int l, r, num, t;
     13 }ques[AC];
     14 
     15 inline int read()
     16 {
     17     int x = 0;char c = getchar();
     18     while(c > '9' || c < '0') c = getchar();
     19     while(c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
     20     return x;
     21 }
     22 
     23 bool cmp(node a, node b)
     24 {
     25     if(a.l / block != b.l / block) return a.l < b.l;
     26     else if(a.r != b.r) return a.r < b.r;
     27     else return a.t < b.t;
     28 }
     29 
     30 void pre()
     31 {
     32     char c;
     33     n = read(), m = read(), block = sqrt(n);
     34     for(Ri i = 1; i <= n; i ++)  s[i] = read();
     35     for(Ri i = 1; i <= m; i ++)
     36     {
     37         cin >> c;
     38         if(c == 'Q')
     39             ques[++cnt].l = read(), ques[cnt].r = read(), ques[cnt].t = tot ,ques[cnt].num = cnt;
     40         else T[++tot].x = read(), T[tot].w = read();
     41     }
     42     sort(ques + 1, ques + cnt + 1, cmp);
     43 }
     44 
     45 void change()//修改时间
     46 {
     47     while(now < tt)
     48     {
     49         for(Ri j = ++now; j <= tt; j ++)
     50         {
     51             int go = T[j].x;
     52             if(!last[j]) last[j] = s[go];//存下上一个时间时的颜色,方便撤销
     53             if(go < L || go > R) s[go] = T[j].w;//如果不在区间内就直接修改
     54             else //不然的话在修改的同时还要更新答案
     55             {
     56                 color[s[go]] --;
     57                 if(!color[s[go]]) X --;
     58                 s[go] = T[j].w;
     59                 if(!color[s[go]]) X ++;
     60                 color[s[go]] ++;
     61             } 
     62         }
     63         now = tt;
     64     }
     65     while(now > tt)
     66     {
     67         for(Ri j = now; j > tt; j --)
     68         {
     69             int go = T[j].x;
     70             if(go < L || go > R) s[go] = last[j];//改回去
     71             else 
     72             {
     73                 color[s[go]] --;
     74                 if(!color[s[go]]) X --;
     75                 s[go] = last[j];
     76                 if(!color[s[go]]) X ++;//如果还没有这个颜色就统计入答案
     77                 color[s[go]] ++;         
     78             }
     79         }
     80         now = tt;
     81     }
     82 }
     83 
     84 void work()
     85 {
     86     now = ques[1].t ,L = ques[1].l ,R = ques[1].r;
     87     for(Ri i = 1; i <= now; i ++)
     88     { 
     89         int go = T[i].x;//error!!!凡是修改了都要记录last
     90         last[i] = s[go], s[go]=T[i].w;
     91     }
     92     for(Ri i = L; i <= R; i ++)
     93     {
     94         if(!color[s[i]]) X ++;
     95         color[s[i]] ++;
     96     }
     97     ans[ques[1].num] = X;
     98     for(Ri i = 2; i <= cnt; i ++)//莫队
     99     {
    100         ll = ques[i].l, rr = ques[i].r, tt = ques[i].t;
    101         while(L < ll)
    102         {
    103             color[s[L]] --;
    104             if(!color[s[L]]) X --;
    105             ++ L;
    106         }
    107         while(L > ll)
    108         {
    109             if(!color[s[-- L]]) X ++;
    110             color[s[L]] ++;
    111         }
    112         while(R > rr)
    113         {
    114             color[s[R]] --;
    115             if(!color[s[R]]) X --;
    116             -- R;
    117         }
    118         while(R < rr)
    119         {
    120             if(!color[s[++ R]]) X ++;
    121             color[s[R]] ++;
    122         }
    123         change();//修改时间放入函数以显简洁
    124         ans[ques[i].num] = X;
    125     }
    126     for(Ri i = 1; i <= cnt; i ++) printf("%d
    ", ans[i]);
    127 }
    128 
    129 int main()
    130 {
    131     freopen("in.in","r",stdin);
    132     pre();
    133     work();
    134     fclose(stdin);
    135     return 0;
    136 }
    View Code


     

  • 相关阅读:
    2021123内部群每日三题清辉PMP
    20211125内部群每日三题清辉PMP
    20211222内部群每日三题清辉PMP
    202215内部群每日三题清辉PMP
    2022117内部群每日三题清辉PMP
    2021126内部群每日三题清辉PMP
    20211126内部群每日三题清辉PMP
    2021122内部群每日三题清辉PMP
    202216内部群每日三题清辉PMP
    20211228内部群每日三题清辉PMP
  • 原文地址:https://www.cnblogs.com/ww3113306/p/8762948.html
Copyright © 2020-2023  润新知