Codeforces

来源:互联网 发布:java future.get 编辑:程序博客网 时间:2024/06/05 19:01

Codeforces - 848C - Goodbye Souvenir

设数列中第 i 个点前一个与 i 颜色相同的点是 prev[i]
那么每次询问的答案是

i=lprev[i]lriprev[i]

如果考虑二维平面上点 (i,prev[i]) 的权值为 iprev[i] 。那么询问转化为求两端点分别为 (l,l)(r,r) 的正方形内框住的点的权值和。
x=iy=prev[i],且考虑到 yx 恒成立,那么上式转化为
yilxirval[i]

由于 yixir ,可以知道询问的区域应该是 x[0,r]y[l,r] 这一段区域。
用树状数组处理 y 这一维,cdq处理 x 这一维就可以做了。

CDQ分治教程
cdq分治时间,每次处理左边的修改对右边询问的影响。
prev 可以用 set 来维护。
时间复杂度最大为 O(nlognlogn)

其实也可以直接求正方形。。如果这样的化把询问转化成四个角的询问就行了。。。这样应该更好理解一点。

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int N = 1e5+7;int n,a[N],m,vis[N],tot;ll c[N],ans[N];bool hq[N];set<int> s[N];struct Node{    //对于修改,x为横轴,y为纵轴,f为修改值,id为0    //对于询问,x为右端点,y为左端点,f为0,id为询问id    int x,y,f,id;}Q[N*6],tmp[N*6];void modify(int x,int y){    if(a[x]==y) return ;    auto i=s[a[x]].find(x);    int p=0;    if(i!=s[a[x]].begin())    {        --i;p=*i;++i;        Q[m++]=(Node){x,p,p-x,0};    }    ++i;    if(i!=s[a[x]].end())    {        Q[m++]=(Node){*i,x,x-*i,0};        if(p) Q[m++]=(Node){*i,p,*i-p,0};    }    s[a[x]].erase(x);    a[x]=y;    i=s[y].insert(x).first;    p=0;    if(i!=s[y].begin())    {        --i;p=*i;++i;        Q[m++]=(Node){x,p,x-p,0};    }    ++i;    if(i!=s[y].end())    {        if(p) Q[m++]=(Node){*i,p,p-*i,0};        Q[m++]=(Node){*i,x,*i-x,0};    }}int lowbit(int x) { return x&-x; }void update(int x,int y){    for(;x<=n;x+=lowbit(x))        if(vis[x]!=tot) vis[x]=tot,c[x]=y;        else c[x]+=y;}ll query(int x){    ll res=0;    for(;x>0;x-=lowbit(x))        res+=(vis[x]==tot?c[x]:0);    return res;}void solve(int L,int R){    if(L>=R) return ;    int mid=(L+R)>>1;    solve(L,mid);    solve(mid+1,R);    ++tot;    int t1=L,t2=mid+1;    for(int i=L;i<=R;++i)    {        if(t2>R||(t1<=mid&&Q[t1].x<=Q[t2].x)) //控制询问的点在(x,x) 的右下角        {            tmp[i]=Q[t1++];            if(tmp[i].id==0) update(n-tmp[i].y+1,tmp[i].f);        }        else        {            tmp[i]=Q[t2++];            if(tmp[i].id) ans[tmp[i].id]+=query(n-tmp[i].y+1); //询问 y=y上方的部分。        }    }    for(int i=L;i<=R;++i) Q[i]=tmp[i];}//二维坐标系中若x=i,那么y=pre[i]。y<x恒成立。int main(){    int q;    scanf("%d%d",&n,&q);    for(int i=1;i<=n;++i)    {        scanf("%d",&a[i]);        auto it=s[a[i]].insert(i).first;        if(it!=s[a[i]].begin()) --it,Q[m++]=(Node){i,*it,i-*it,0};    }    for(int i=1;i<=q;++i)    {        int op,l,r;        scanf("%d%d%d",&op,&l,&r);        if(op==1) modify(l,r);        else hq[i]=true,Q[m++]=(Node){r,l,0,i};    }    solve(0,m-1);    for(int i=1;i<=q;++i) if(hq[i]) printf("%I64d\n",ans[i]);    return 0;}