#4139. 白白的(baibaide)

Posted xjqxjq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#4139. 白白的(baibaide)相关的知识,希望对你有一定的参考价值。

题意
内存限制:1024 MiB
时间限制:2000 ms

有一个长度为 $n$ 的序列 $a_1, a_2, dots, a_n$,一开始每个位置都是白色。如果一个区间中每个位置都是白色,则称这是一个白白的区间。如果一个白白的区间向左或向右延长后都不是白白的区间了,则称这是一个极长的白白的区间。有 $q$ 次操作,每次操作会修改某个位置的值,或者把某个位置变成黑色。每次操作后,求所有极长的白白的区间中含有的逆序对数的异或和。强制在线。

$n ≤ 150000,q ≤ 20000,0 ≤ a_i ≤ 10^9,1 ≤ x ≤ n,0 ≤ y ≤ 10^9$
题解
容易想到启发式分裂,并用树状数组+主席树维护逆序对个数,可惜这样是 $O(nlog^3n)$
考虑用 $Splay$ 维护一段白白的区间,每次分裂减少一个数后所造成的影响可以通过查询其rank求出,修改数的时候就照样用树套树维护即可,效率 $O(nlog^2n+qlog^3n)$

代码

#include <bits/stdc++.h>
#define mid ((l+r)>>1)
#define LL long long
#define I inline
using namespace std;
const int N=1.5e5+5,ax=1e9;
set<int>st;set<int>::iterator it;LL Ans,ans[N],lst;
int tt,n,q,a[N],s[N*250],ls[N*250],rs[N*250],T[N],d[N],rt[N];
int son[N*40][2],fa[N*40],sz[N*40],tot,w[N*40],cnt[N*40];
I void update(int& x,int l,int r,int p,int v){
    if (!x) x=++tt;s[x]+=v;
    if (l==r) return;
    if (mid>=p) update(ls[x],l,mid,p,v);
    else update(rs[x],mid+1,r,p,v);
}
I void update(int x,int v){
    for (int i=x;i<=n;i+=i&-i) update(T[i],0,ax,a[x],v);
}
I int query(int x,int l,int r,int L,int R){
    if (!x) return 0;int res=0;
    if (L<=l && r<=R) return s[x];
    if (mid<R) res=query(rs[x],mid+1,r,L,R);
    if (mid>=L) res+=query(ls[x],l,mid,L,R);
    return res;
}
I int query(int L,int R,int l,int r){
    if (L>=R || l>r) return 0;int res=0;
    for (;R;R-=R&-R) res+=query(T[R],0,ax,l,r);
    for (;L;L-=L&-L) res-=query(T[L],0,ax,l,r);
    return res;
}
#define Ls son[x][0]
#define Rs son[x][1]
I void update(int x){sz[x]=sz[Ls]+sz[Rs]+cnt[x];}
I int init(){
    tot+=2;sz[tot-1]=sz[tot]=cnt[tot-1]=cnt[tot]=0;
    son[tot][1]=tot-1;fa[tot-1]=tot;
    w[tot]=-1;w[tot-1]=ax+1;return tot;
}
I bool iden(int x,int y){return son[y][1]==x;}
I void rotate(int x){
    int y=fa[x],z=fa[y],k=iden(x,y);
    fa[x]=z;son[z][iden(y,z)]=x;
    fa[son[x][k^1]]=y;
    son[y][k]=son[x][k^1];
    fa[y]=x;son[x][k^1]=y;
    update(y);update(x);
}
I void splay(int x,int& F){
    if (!x) return;F=0;
    while(fa[x]!=F){
        int y=fa[x],z=fa[y];
        if (z!=F){
            if (iden(x,y)^iden(y,z)) rotate(x);
            else rotate(y);
        }rotate(x);
    }F=x;
}
I void ins(int& r,int v,int x){
    int u=r,F=0;
    while(u && w[u]!=v)
        F=u,u=son[u][v>w[F]];
    if (u){
        splay(u,r);
        cnt[u]+=x;update(u);
        return;
    }
    fa[u=++tot]=F;w[u]=v;
    sz[u]=cnt[u]=1;
    son[u][0]=son[u][1]=0;
    if (F) son[F][v>w[F]]=u;
    splay(u,r);
}
I int query(int& r,int v,bool ty){
    int u=r;
    while(u && w[u]!=v)
        u=son[u][v>w[u]];
    splay(u,r);
    return sz[son[u][ty]];
}
int main(){
    scanf("%d%d",&n,&q);
    st.insert(1e9);rt[1]=init();
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]),update(i,1),
        Ans+=query(0,i-1,a[i]+1,ax),ins(rt[1],a[i],1);
    ans[1]=Ans;st.insert(1);d[1]=n;
    for (int op,x,y,l,r;q--;){
        LL X,Y;scanf("%d%lld",&op,&X);x=(int)(X^lst);
        it=st.upper_bound(x);it--;l=(*it);r=d[l];Ans^=ans[l];
        if (op){
            d[l]=x-1;if (x<r) d[x+1]=r,st.insert(x+1);
            LL A=query(l-1,x-1,a[x]+1,ax)+query(x,r,0,a[x]-1);
            ins(rt[l],a[x],-1);
            if (x-l<r-x){
                rt[x+1]=rt[l];rt[l]=init();
                ans[x+1]=ans[l];ans[l]=0;
                for (int i=l;i<x;i++)
                    A+=query(rt[x+1],a[i],0),
                    ins(rt[x+1],a[i],-1),
                    ins(rt[l],a[i],1),
                    ans[l]+=query(rt[l],a[i],1);
                ans[x+1]-=A;Ans^=(ans[x+1]^ans[l]);
            }
            else{
                ans[x+1]=0;
                if (r>x) rt[x+1]=init();
                for (int i=r;i>x;i--)
                    A+=query(rt[l],a[i],1),
                    ins(rt[l],a[i],-1),
                    ins(rt[x+1],a[i],1),
                    ans[x+1]+=query(rt[x+1],a[i],0);
                ans[l]-=A;Ans^=(ans[x+1]^ans[l]);
            }
        }
        else{
            scanf("%lld",&Y);y=(int)(Y^lst);
            ins(rt[l],a[x],-1);ins(rt[l],y,1);
            ans[l]-=query(l-1,x-1,a[x]+1,ax);
            ans[l]-=query(x,r,0,a[x]-1);
            update(x,-1);a[x]=y;update(x,1);
            ans[l]+=query(l-1,x-1,a[x]+1,ax);
            ans[l]+=query(x,r,0,a[x]-1);
            Ans^=ans[l];
        }
        printf("%lld
",Ans);lst=Ans;
    }
    return 0;
}

 

以上是关于#4139. 白白的(baibaide)的主要内容,如果未能解决你的问题,请参考以下文章

P4139 上帝与集合的正确用法

Luogu 4139 上帝与集合的正确用法

洛谷 P4139 上帝与集合的正确用法

Luogu4139 上帝与集合的正确用法 拓展欧拉定理

题解 P4139 上帝与集合的正确用法

Luogu[P4139] 上帝与集合的正确用法(扩展欧拉定理)