• 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
    ",ans[i]);
    111 }
  • 相关阅读:
    zabbix邮箱告警配置
    kali linux 开启配置ssh服务
    自主访问控制和强制访问控制
    Eddy's picture
    Connect the Cities--hdoj
    Dark roads--hdoj
    Ice_cream’s world III
    国王的烦恼---nyoj
    Tree
    Jungle Roads --hdoj
  • 原文地址:https://www.cnblogs.com/refun/p/10485855.html
Copyright © 2020-2023  润新知