4 3
6 0 10 1
1 2
1 0
1 2
1
1
0
先一遍归并排序算出初始答案。
对于 0 操作,我们需要计算改变的那一位对答案的贡献。
这个就是单点修改+区间查询比 x 大的数的个数,树状数组套权值线段树即可(动态开点)。
对于 1 操作,我们要分裂区间,可以考虑启发式合并,扫短的那边算贡献。
但如果用前面的树套树来算,这部分复杂度将达到 O ( Q l o g 3 n ) O(Q\ log^3n) O(Q log3n) ,不能接受。
我们发现由于查询时查询的区间(长的那边)是固定的,这是一个突破口。
再开一个一维的权值线段树来维护就可以了!
每次分裂区间时将短的那边多开成一个线段树(最多 Q 个)即可。
这样计算复杂度就是 O ( Q l o g 2 n ) O(Q\ log^2n) O(Q log2n) 了。
总时间复杂度 O ( ( N + Q ) l o g 2 n ) O((N+Q)\ log^2n) O((N+Q) log2n) ,空间复杂度 O ( N l o g 2 n ) O(N\ log^2n) O(N log2n) 。
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=150005,inf=1e9+1;
struct data
{
int s,l,r;
}f[N*30*17];
int n,q,tot,qx,qy,num;
LL ans,cnt;
int a[N],b[N],c[N];
int rt[N],rt1[N],bel[N];
LL val[N];
set<int>ss;
set<int>::iterator it;
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
void solve(int l,int r)
{
if(l>=r) return;
int mid=l+r>>1;
solve(l,mid);
solve(mid+1,r);
int j=l,k=mid+1,s=l-1;
while(j<=mid && k<=r)
if(b[k]<b[j])
{
c[++s]=b[k++];
cnt+=mid-j+1;
}else c[++s]=b[j++];
while(j<=mid) c[++s]=b[j++];
while(k<=r) c[++s]=b[k++];
for(int i=l;i<=r;i++) b[i]=c[i];
}
void change(int &v,int l,int r)
{
if(!v) v=++tot;
f[v].s+=qy;
if(l==r) return;
int mid=l+r>>1;
if(qx<=mid) change(f[v].l,l,mid); else change(f[v].r,mid+1,r);
}
int find(int v,int l,int r)
{
if(!v) return 0;
if(qx<=l && r<=qy) return f[v].s;
int mid=l+r>>1,s=0;
if(qx<=mid) s=find(f[v].l,l,mid);
if(qy>mid) s+=find(f[v].r,mid+1,r);
return s;
}
inline void add(int x,int y)
{
qx=y,qy=1;
while(x<=n)
{
change(rt[x],0,inf);
x+=x&-x;
}
}
inline void del(int x,int y)
{
qx=y,qy=-1;
while(x<=n)
{
change(rt[x],0,inf);
x+=x&-x;
}
}
inline LL get(int x,int y,int z)
{
LL s=0;
if(y>z) return 0;
qx=y,qy=z;
while(x)
{
s+=find(rt[x],0,inf);
x-=x&-x;
}
return s;
}
int main()
{
freopen("baibaide.in","r",stdin);
freopen("baibaide.out","w",stdout);
n=read(),q=read();
for(int i=1;i<=n;i++) a[i]=b[i]=read();
solve(1,n);
ss.insert(0);
ss.insert(n+1);
for(int i=1;i<=n;i++) add(i,a[i]);
val[num=1]=ans=cnt;
for(int i=1;i<=n;i++)
{
bel[i]=num;
qx=a[i],qy=1;
change(rt1[num],0,inf);
}
for(int j=1;j<=q;j++)
{
int op=read(),x=read();
if(j>1) x^=ans;
it=ss.upper_bound(x);
int r=*it,l=*--it;
l++,r--;
if(!op)
{
int y=read();
if(j>1) y^=ans;
ans^=val[bel[l]];
LL sum=get(x-1,a[x]+1,inf)-get(l-1,a[x]+1,inf);
sum+=get(r,0,a[x]-1)-get(x,0,a[x]-1);
val[bel[l]]-=sum;
del(x,a[x]);
qx=a[x],qy=-1;
change(rt1[bel[l]],0,inf);
a[x]=y;
add(x,y);
qx=y,qy=1;
change(rt1[bel[l]],0,inf);
sum=get(x-1,y+1,inf)-get(l-1,y+1,inf);
sum+=get(r,0,y-1)-get(x,0,y-1);
val[bel[l]]+=sum;
ans^=val[bel[l]];
}else
{
ss.insert(x);
if(x-l<r-x)
{
int pos=bel[r];
for(int i=l;i<=x;i++)
{
qx=a[i],qy=-1;
change(rt1[pos],0,inf);
}
ans^=val[pos];
for(int i=l;i<=x;i++)
{
qx=0,qy=a[i]-1;
val[pos]-=find(rt1[pos],0,inf);
}
if(l<x)
{
num++;
for(int i=l;i<x;i++) bel[i]=num;
for(int i=l;i<x;i++)
{
qx=a[i],qy=1;
change(rt1[num],0,inf);
}
int len=cnt=0;
for(int i=l;i<x;i++) b[++len]=a[i];
solve(1,len);
val[num]=cnt;
ans^=cnt;
qx=a[x]+1,qy=inf;
cnt+=find(rt1[num],0,inf);
val[pos]-=cnt;
}
ans^=val[pos];
}else
{
int pos=bel[l];
for(int i=x;i<=r;i++)
{
qx=a[i],qy=-1;
change(rt1[pos],0,inf);
}
ans^=val[pos];
for(int i=x;i<=r;i++)
{
qx=a[i]+1,qy=inf;
val[pos]-=find(rt1[pos],0,inf);
}
if(x<r)
{
num++;
for(int i=x+1;i<=r;i++) bel[i]=num;
for(int i=x+1;i<=r;i++)
{
qx=a[i],qy=1;
change(rt1[num],0,inf);
}
int len=cnt=0;
for(int i=x+1;i<=r;i++) b[++len]=a[i];
solve(1,len);
val[num]=cnt;
ans^=cnt;
qx=0,qy=a[x]-1;
cnt+=find(rt1[num],0,inf);
val[pos]-=cnt;
}
ans^=val[pos];
}
}
printf("%lld\n",ans);
}
return 0;
}