dtoj#4139. 白白的(baibaide)

题目描述:

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

输入:

第一行两个正整数 $n,q$ 。

第二行 $n$ 个正整数 $a1,a2,......,an$ 。

接下来 $q$ 行,每行表示一次操作,每行的第一个数表示操作的种类:

• $0$ $x$ $y$ 表示把 $a_{x}$ 改为 $y$ 

• $1$ $x$ 表示把第 $x$ 个位置变成黑色

保证每次操作时的第 $x$ 个位置是白色的。

$x$ 和 $y$ 需要异或上一次输出的答案(若是第一次操作则无需异或)。

算法标签:树状数组套主席树,平衡树/splay,set

思路:

对于单次修改可以用树状数组套主席树进行,而对于分割区间的操作,我们用 $splay$ 维护,每次把被分割区间中小的那一部分一个一个删除建成一棵新的平衡树,由于,每次选择小的,效率是和启发式合并一样的 $nlog$ ,加上单次修改平衡树,效率是 $nlogn$ 。修改单点数值的树状数组套主席树效率也是 $nlogn$ 。

以下代码:

#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=2e5+5,mx=1e9+1;
set<int> s;
set<int>::iterator it;
LL ans,res[N],lst;
int n,Q,a[N],rt[N],nt,L[N],Rt[N];
struct node{
    int l,r,num;
}t[N*250];
il LL read(){
    LL x,f=1;char ch;
    _(!)ch=='-'?f=-1:f;x=ch^48;
    _()x=(x<<1)+(x<<3)+(ch^48);
    return f*x;
}
il int query(int x,int l,int r,int ql,int qr){
    if(!x)return 0;
    if(ql<=l&&r<=qr)return t[x].num;
    int mid=(l+r)>>1,res=0;
    if(ql<=mid)res=query(t[x].l,l,mid,ql,qr);
    if(mid<qr)res+=query(t[x].r,mid+1,r,ql,qr);
    return res;
}
il int Query(int L,int R,int l,int r){
    //printf("%d %d %d %d 
",L,R,l,r);
    if(L==R)return 0;if(l>r)return 0;
    int ans=0;
    for(;R;R-=R&-R)ans+=query(rt[R],1,mx,l,r);
    for(;L;L-=L&-L)ans-=query(rt[L],1,mx,l,r);
    //printf("!!%d 
",ans);
    return ans;
}
il void insert(int &x,int l,int r,int pos,int v){
    if(!x)x=++nt;t[x].num+=v;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)insert(t[x].l,l,mid,pos,v);
    else insert(t[x].r,mid+1,r,pos,v);
}
il void Insert(int P,int pos,int v){
    for(;P<=n;P+=P&-P)insert(rt[P],1,mx,pos,v);
}
class Splay{
public:
    int ch[N*40][2],fa[N*40],sz[N*40],tot,val[N*40],nm[N*40];
    il void update(int x){
        sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+nm[x];
    }
    il int init(){
        tot+=2;
        fa[tot]=tot-1;ch[tot-1][1]=tot;
        val[tot]=mx+1;val[tot-1]=0;
        sz[tot-1]=sz[tot]=nm[tot-1]=nm[tot]=0;
        return tot-1;
    }
    il int findx(int x,int num){
        if(!x)return 0;
        if(val[x]==num)return x;
        if(val[x]<num){
            int kk=findx(ch[x][1],num);
            return (kk?kk:x);
        }
        return findx(ch[x][0],num);
    }
    il int findd(int x,int num){
        if(!x)return 0;
        if(val[x]==num)return x;
        if(val[x]>num){
            int kk=findd(ch[x][0],num);
            return (kk?kk:x);
        }
        return findd(ch[x][1],num);
    }
    il int gs(int x){
        return x==ch[fa[x]][1];
    }
    il void rotate(int x,int &k){
        int y=fa[x],z=fa[y],tp=gs(x);
        if(y==k)k=x;else ch[z][gs(y)]=x;
        ch[y][tp]=ch[x][tp^1];fa[ch[x][tp^1]]=y;
        ch[x][tp^1]=y;fa[y]=x;fa[x]=z;
        update(y);update(x);
    }
    il void splay(int x,int &k){
        while(x!=k){
            int y=fa[x],z=fa[y];
            if(y!=k)
                rotate((gs(x)==gs(y))?y:x,k);
            rotate(x,k);
        }
    }
    il void insert(int id,int x,int v){
        int now=findx(Rt[id],x);
        if(val[now]==x){
            splay(now,Rt[id]);
            nm[now]+=v;update(now);
            return;
        }
        int rr=findd(Rt[id],x);
        splay(now,Rt[id]);splay(rr,ch[now][1]);
        tot++;val[tot]=x;nm[tot]=sz[tot]=1;
        fa[tot]=rr;ch[rr][0]=tot;
        update(rr);update(now);
    }
}T;
int main()
{
    n=read();Q=read();
    for(int i=1;i<=n;i++)a[i]=read()+1;
    s.insert(n);L[n]=1;
    for(int i=1;i<=n;i++){
        if(i!=1&&a[i]!=mx)ans+=Query(0,i-1,a[i]+1,mx);
        Insert(i,a[i],1);
    }
    res[n]=ans;Rt[n]=T.init();
    for(int i=1;i<=n;i++)T.insert(n,a[i],1);
    while(Q--){
        int op=read();
        int x=read()^lst;
        it=s.lower_bound(x);
        int r=*it,l;
        l=L[r];ans^=res[r];
        if(op){
            L[r]=x+1;L[x-1]=l;
            s.insert(x-1);
            LL res1=1ll*Query(l-1,x-1,a[x]+1,mx)+Query(x,r,1,a[x]-1);
            res[x-1]=0;
            T.insert(r,a[x],-1);
            if(x-l<r-x){
                if(l!=x)Rt[x-1]=T.init();
                for(int i=l;i<x;i++){
                    T.insert(r,a[i],-1);
                    int k=T.findd(Rt[r],a[i]);
                    T.splay(k,Rt[r]);res1+=T.sz[T.ch[k][0]];
                    T.insert(x-1,a[i],1);
                    k=T.findd(Rt[x-1],a[i]);
                    T.splay(k,Rt[x-1]);
                    res[x-1]+=T.sz[T.ch[k][1]];
                }
                res[r]-=res1;
                ans^=res[x-1];ans^=res[r];
            }
            else{
                swap(res[r],res[x-1]);res[r]=0;
                swap(Rt[r],Rt[x-1]);Rt[r]=T.init();
                for(int i=r;i>x;i--){
                    T.insert(x-1,a[i],-1);
                    int k=T.findd(Rt[x-1],a[i]);
                    T.splay(k,Rt[x-1]);res1+=T.sz[T.ch[k][1]];
                    T.insert(r,a[i],1);
                    k=T.findd(Rt[r],a[i]);
                    T.splay(k,Rt[r]);
                    res[r]+=T.sz[T.ch[k][0]];
                }
                res[x-1]-=res1;
                ans^=res[r];ans^=res[x-1];
            }
            printf("%lld
",ans);lst=ans;
        }
        else{
            int y=read()^lst;y++;
            T.insert(r,a[x],-1);T.insert(r,y,1);
            res[r]-=Query(l-1,x-1,a[x]+1,mx);
            res[r]-=Query(x,r,1,a[x]-1);
            Insert(x,a[x],-1);a[x]=y;Insert(x,a[x],1);
            res[r]+=Query(l-1,x-1,a[x]+1,mx);
            res[r]+=Query(x,r,1,a[x]-1);
            ans^=res[r];
            printf("%lld
",ans);lst=ans;
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Jessie-/p/10416243.html