7.14的某毒瘤题 维护队列题解

传送

思路by lyd,ych

我们参考选择客栈的思路,设pre[i]是i前面一个和i颜色相同的画笔,col[i]记录i的颜色

我们发现,当pre[i]<l<=i<=r时,col[i]第一次出现在区间[l,r]中

我们的问题是区间[l,r]中有多少不同的颜色,也就是统计区间[l,r]中有多少颜色是第一次出现

这样查询就被我们切掉了

然后就是令人崩溃的修改。

我们修改一个点i,需要知道pre[i],满足pre[j]=i的j,以及更改之后pre[i]是多少

我们可以对每一个颜色搞一个set(最多1e6颜色不会爆空间的)。在修改点i的时候,在set里面找到i的后继,令pre[i的后继]=i的前驱,然后把i从原来的set中删掉,更改col[i]。在新的set里面更新pre[i]。

注意:每个set要先插入0,inf以防找到一些神奇的玩意。

正解:带修莫队我不会

不会

差点T飞的代码

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    char ch=getchar();
    int x=0;bool f=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return f?-x:x;
}
const int inf=214748364;
set <int> qaq[1000009];
set <int>::iterator qwq,www,owo;
int n,m,col[500009],pre[500009],lst[500009];
int main()
{
    n=read();
    m=read();
    for(int i=1;i<=n;i++)
     qaq[i].insert(0),qaq[i].insert(inf);
    for(int i=1;i<=n;i++)
     {
         col[i]=read();
         pre[i]=lst[col[i]];
         lst[col[i]]=i;
         qaq[col[i]].insert(i);
     }
     for(int i=1;i<=m;i++)
     {
         char cz=getchar();
         while(cz!='Q'&&cz!='R')cz=getchar();
         int gs1=read(),gs2=read();//搞事1,搞事2
         if(cz=='Q')
         {
             int gs=0;
             for(int i=gs1;i<=gs2;i++)
               if(pre[i]<gs1)gs++;
             printf("%d\n",gs);  
        }
        if(cz=='R')
        {
       if(qaq[gs2].size()==0)qaq[gs2].insert(0);qaq[gs2].insert(inf);    
         qwq=qaq[col[gs1]].find(gs1);
         qwq++;www=qwq;qwq--;qwq--;owo=qwq;
          if(*www!=inf)pre[*www]=*owo;
         qaq[col[gs1]].erase(gs1);col[gs1]=gs2;
         qaq[gs2].insert(gs1); 
         qwq=qaq[gs2].find(gs1);
         qwq--;
         pre[gs1]=*qwq;
         qwq++;qwq++;
         if(*qwq!=inf)
          pre[*qwq]=gs1;
        }
     }
}

 

posted @ 2019-07-23 18:02  千载煜  阅读(132)  评论(0编辑  收藏  举报