CF848C:Goodbye Souvenir(CDQ分治)

Description

给定长度为$n$的数组, 定义数字$X$在$[l,r]$内的值为数字$X$在$[l,r]$内最后一次出现位置的下标减去第一次出现位置的下标
给定$m$次询问, 每次询问有三个整数$a,b,c$询问规则如下:
当$a=1$时, 将数组内第$b$个元素更改为$c$
当$a=2$时, 求区间$[b,c]$所有数字的值的和

Input

第一行两个整数$n$,$m$
第二行$n$个整数, 表示数组
第$3$到$3+m$行, 每行三个整数, 表示每次询问。

Output

对于每次$a=2$的询问, 输出一个整数表示答案

Sample Input1

7 6
1 2 3 1 3 2 1
2 3 7
2 1 3
1 7 2
1 3 2
2 1 6
2 5 7

Sample Output1

5
0
7
1

Sample Input2

7 5
1 3 2 1 4 2 3
1 1 4
2 2 3
1 1 7
2 4 5
1 1 7

Sample Output2

0
0

Solution

设初始每个位置对应点$(i,pre[i])$,权值为$i-pre[i]$。可以把初始位置上的点看成矩形单点加操作。
$pre[i]$为$i$这个位置的数上一次出现的位置,若没有则为$0$。
那么查询区间$[L,R]$就相当于查询左下$(L,L)$右上$(R,R)$的矩形的权值和(写写画画可能比较容易明白),可以$CDQ$。
考虑一次修改会影响什么?设$i$位置把$x$修改成$y$,只会影响和$i$相邻的$x$和$y$,这个可以用$set$维护,然后看成若干矩形单点加操作。
那么就可以写一个只有单点加和矩形求和的$CDQ$分治了。

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<set>
  5 #define N (700009)
  6 #define LL long long
  7 using namespace std;
  8 
  9 struct Que{int x,y,opt,v;}Q[N],tmp[N];
 10 int n,m,cnt,q_num;
 11 int a[N],b[N],pre[N];
 12 LL c[N],ans[N];
 13 set<int>S[N];
 14 set<int>::iterator it;
 15 
 16 inline int read()
 17 {
 18     int x=0,w=1; char c=getchar();
 19     while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();}
 20     while (c>='0' && c<='9') x=x*10+c-'0', c=getchar();
 21     return x*w;
 22 }
 23 
 24 void Update(int x,int k)
 25 {
 26     for (; x<=n+1; x+=(x&-x)) c[x]+=k;
 27 }
 28 
 29 LL Query(int x)
 30 {
 31     LL ans=0;
 32     for (; x; x-=(x&-x)) ans+=c[x];
 33     return ans;
 34 }
 35 
 36 void CDQ(int l,int r)
 37 {
 38     if (l==r) return;
 39     int mid=(l+r)>>1;
 40     CDQ(l,mid); CDQ(mid+1,r);
 41     int i=l,j=mid+1,k=l-1;
 42     while (i<=mid || j<=r)
 43         if (j>r || i<=mid && (Q[i].x<Q[j].x || Q[i].x==Q[j].x && Q[i].opt<Q[j].opt))
 44         {
 45             if (Q[i].opt==1) Update(Q[i].y,Q[i].v);
 46             tmp[++k]=Q[i]; ++i;
 47         }
 48         else
 49         {
 50             if (Q[j].opt==2)
 51             {
 52                 if (Q[j].v>0) ans[Q[j].v]+=Query(Q[j].y);
 53                 else ans[-Q[j].v]-=Query(Q[j].y);
 54             }
 55             tmp[++k]=Q[j]; ++j;
 56         }
 57     for (int i=l; i<=mid; ++i)
 58         if (Q[i].opt==1) Update(Q[i].y,-Q[i].v);
 59     for (int i=l; i<=r; ++i) Q[i]=tmp[i];
 60 }
 61 int main()
 62 {
 63     n=read(); m=read();
 64     for (int i=1; i<=n; ++i)
 65     {
 66         a[i]=read(); pre[i]=b[a[i]]; b[a[i]]=i;
 67         S[a[i]].insert(i); Q[++q_num]=(Que){i,pre[i],1,i-pre[i]};
 68     }
 69     for (int i=1; i<=m; ++i)
 70     {
 71         int opt=read(),x=read(),y=read();
 72         if (opt==1)
 73         {
 74             int p1=0,n1=0;//前驱 后继 
 75             it=S[a[x]].find(x);
 76             if (it!=S[a[x]].begin()) --it, p1=*it, ++it;
 77             if ((++it)!=S[a[x]].end()) n1=*it; --it;
 78             S[a[x]].erase(*it); Q[++q_num]=(Que){x,pre[x],1,pre[x]-x};
 79             if (n1)
 80             {
 81                 Q[++q_num]=(Que){n1,pre[n1],1,pre[n1]-n1};
 82                 pre[n1]=p1;
 83                 Q[++q_num]=(Que){n1,pre[n1],1,n1-pre[n1]};
 84             }
 85             
 86             int p2=0,n2=0;
 87             a[x]=y; S[a[x]].insert(x);
 88             it=S[a[x]].find(x);
 89             if (it!=S[a[x]].begin()) --it, p2=*it, ++it;
 90             if ((++it)!=S[a[x]].end()) n2=*it; --it;
 91             pre[x]=p2; Q[++q_num]=(Que){x,pre[x],1,x-pre[x]};
 92             if (n2)
 93             {
 94                 Q[++q_num]=(Que){n2,pre[n2],1,pre[n2]-n2};
 95                 pre[n2]=x;
 96                 Q[++q_num]=(Que){n2,pre[n2],1,n2-pre[n2]};
 97             }
 98         }
 99         else
100         {
101             ++cnt;
102             Q[++q_num]=(Que){x-1,x-1,2,cnt};
103             Q[++q_num]=(Que){y,y,2,cnt};
104             Q[++q_num]=(Que){x-1,y,2,-cnt};
105             Q[++q_num]=(Que){y,x-1,2,-cnt};
106         }
107     }
108     for (int i=1; i<=q_num; ++i) Q[i].x++, Q[i].y++;
109     CDQ(1,q_num);
110     for (int i=1; i<=cnt; ++i) printf("%lld\n",ans[i]);
111 }
posted @ 2019-03-06 20:41  Refun  阅读(431)  评论(0编辑  收藏  举报