• bzoj 2453 : 维护队列 带修莫队


    2453: 维护队列

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 952  Solved: 432
    [Submit][Status][Discuss]

    Description

    你小时候玩过弹珠吗?
    小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N。为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少。当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色。但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助。

    Input

    输入文件第一行包含两个整数N和M。
    第二行N个整数,表示初始队列中弹珠的颜色。
    接下来M行,每行的形式为“Q L R”或“R x c”,“Q L R”表示A想知道从队列第L个弹珠到第R个弹珠中,一共有多少不同颜色的弹珠,“R x c”表示A把x位置上的弹珠换成了c颜色。

    Output

    对于每个Q操作,输出一行表示询问结果。

    Sample Input


    2 3
    1 2
    Q 1 2
    R 1 2
    Q 1 2

    Sample Output

    2
    1

    HINT

    对于100%的数据,有1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。

    Source

    2011福建集训

      把询问和修改分开排序,修改按时间排,询问以左端点所在块为第一关键字,右端点所在块为第二关键字,时间为第三关键字排序。

      维护左右时间三个指针,不断修改还原。

      块大小为$n^{frac{2}{3}}$。

      左指针每个询问走$n^{frac{2}{3}}$。

      右指针同理,不过要多上每次总从左走到右的复杂度,总共$n imes n^{frac{2}{3}}+n imes n^{frac{1}{3}}$。

      时间指针每次左右端点所在块变化重新开始走,一共$n^{frac{2}{3}}$个不同的左右块匹配数,复杂度$n imes n^{frac{2}{3}}$.

      好像块开100比较快。

      (写莫队时一定要先把lr往两边移,再向中间移)

      

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #define d 100
      6 #define N 10005
      7 using namespace std;
      8 int n,m;
      9 int c[N];
     10 struct node
     11 {
     12     int l,r,t,pr;
     13     node(){l=r=t=0;}
     14 }q[N],g[N];
     15 int cnt1,cnt2;
     16 bool cmp1(const node &aa,const node &bb)
     17 {
     18     return aa.t<bb.t;
     19 }
     20 int be1[N],be2[N];
     21 bool cmp2(const node &aa,const node &bb)
     22 {
     23     if(be1[aa.l]==be1[bb.l])
     24     {
     25         if(be2[aa.r]==be2[bb.r])return aa.t<bb.t;
     26         return aa.r<bb.r;
     27     }
     28     return aa.l<bb.l;
     29 }
     30 int ans[N];
     31 int now[N*100],cnt;
     32 void solve()
     33 {
     34     int p1,p2,p;
     35     memset(now,0,sizeof(now));
     36     now[c[1]]=1;cnt=1;g[cnt1+1].t=10005;
     37     p=p1=1;
     38     p2=0;
     39     for(int i=1;i<=cnt2;i++)
     40     {
     41         while(g[p2+1].t<q[i].t)
     42         {
     43             p2++;
     44             int tmp=c[g[p2].l];
     45             g[p2].pr=tmp;
     46             c[g[p2].l]=g[p2].r;
     47             if(g[p2].l<=p&&g[p2].l>=p1)
     48             {
     49                 now[tmp]--;
     50                 if(!now[tmp])cnt--;
     51                 now[g[p2].r]++;
     52                 if(now[g[p2].r]==1)cnt++;
     53             }
     54         }
     55         while(g[p2].t>q[i].t)
     56         {
     57             
     58             c[g[p2].l]=g[p2].pr;
     59             if(g[p2].l<=p&&g[p2].l>=p1)
     60             {
     61                 now[g[p2].r]--;
     62                 if(!now[g[p2].r])cnt--;
     63                 now[g[p2].pr]++;
     64                 if(now[g[p2].pr]==1)cnt++;
     65             }
     66             p2--;
     67         }
     68         while(p<q[i].r)
     69         {
     70             p++;now[c[p]]++;
     71             if(now[c[p]]==1)cnt++;
     72         }
     73         while(p>q[i].r)
     74         {
     75             now[c[p]]--;if(!now[c[p]])cnt--;
     76             p--;
     77         }
     78         while(p1<q[i].l)
     79         {
     80             now[c[p1]]--;if(!now[c[p1]])cnt--;
     81             p1++;
     82         }
     83         while(p1>q[i].l)
     84         {
     85             p1--;now[c[p1]]++;
     86             if(now[c[p1]]==1)cnt++;
     87         }
     88         ans[q[i].t]=cnt;
     89     }
     90 }
     91 int main()
     92 {
     93     scanf("%d%d",&n,&m);
     94     for(int i=1;i<=n;i++)scanf("%d",&c[i]);
     95     for(int i=1;i<=n;i++)
     96     {
     97         be1[i]=be2[i]=(i-1)/d+1;
     98     }
     99     memset(ans,-1,sizeof(ans));
    100     char s[2];
    101     for(int i=1;i<=m;i++)
    102     {
    103         scanf("%s",s);
    104         if(s[0]=='R')
    105         {
    106             cnt1++;
    107             scanf("%d%d",&g[cnt1].l,&g[cnt1].r);
    108             g[cnt1].t=i;
    109         }
    110         else
    111         {
    112             cnt2++;
    113             scanf("%d%d",&q[cnt2].l,&q[cnt2].r);
    114             q[cnt2].t=i;
    115         }
    116     }
    117     sort(q+1,q+cnt2+1,cmp2);
    118     sort(g+1,g+cnt1+1,cmp1);
    119     solve();
    120     for(int i=1;i<=m;i++)
    121     {
    122         if(ans[i]!=-1)printf("%d
    ",ans[i]);
    123     }
    124     return 0;
    125 }
  • 相关阅读:
    POJ 3678 Katu Puzzle(POJ 六道2SAT之一)
    POJ 2942 Knights of the Round Table ★(点双连通分量+二分图判定)
    POJ 3207 Ikki's Story IV Panda's Trick (POJ 六道2SAT之一)
    POJ 2762 Going from u to v or from v to u?(有向图单向连通)
    POJ 3207 Ikki's Story IV Panda's Trick (POJ 六道2SAT之一)
    POJ 3694 Network ★(边双连通分量+并查集缩点+LCA)
    Visual C#常用函数和方法集汇总
    软件项目版本号的命名规则及格式
    软件项目版本号的命名规则及格式
    软件项目版本号的命名规则及格式
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6536135.html
Copyright © 2020-2023  润新知