题目大意:带修改、强制在线的区间逆序对
将之前3744TLE了的某个做法重写了一发 把其中一些预处理改成了树状数组 不得不说树状数组常数还是小啊
令g[i][j](i<=j)表示第i块中的元素与第i~j块中的元素之间的逆序对数 第一维暴力第二维树状数组维护前缀和
equals[i][j]表示前i块之内j的数量 这个直接暴力即可
smaller[i][j]表示前i块之内小于等于j的数的数量 第一维暴力第二维树状数组
修改时都维护一遍 查询时 首先我们把区间分为三块
令A为左侧零碎部分 B为中间成块部分 C为右侧零碎部分
BB直接调用g数组 时间复杂度O(√nlogn)
AB利用equals和smaller数组求出对于A中每个元素B中比该元素小的数的数量 时间复杂度O(√nlogn)
BC利用B部分大小和smaller数组求出对于C中每个元素B中比该元素大的数的数量 时间复杂度O(√nlogn)
然后把A部分和C部分都放在一起 上BIT(我偷懒写了Merge_Sort) AA、AC、CC就都出来了
总时间复杂度不超过O(n√nlogn)
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 50500 #define SQRT_M 250 using namespace std; int n,m,block,ans; int a[M],b[M]; int f[SQRT_M][SQRT_M]; //f[i][i]表示第i块内部的逆序对数 //f[i][j](i<j)表示第i块中的元素与第j块中的元素之间的逆序对数 int g[SQRT_M][SQRT_M]; //g[i][j](i<=j)表示第i块中的元素与第i~j块中的元素之间的逆序对数 //第一维暴力第二维树状数组前缀和 //向上修改向下查询 int equals[SQRT_M][M]; int smaller[SQRT_M][M]; /* equals[i][j]表示前i块之内j的数量 直接暴力 smaller[i][j]表示前i块之内小于等于j的数的数量 向上修改向下查询 第一维暴力第二维树状数组 */ int l[SQRT_M],r[SQRT_M],belong[M]; int Merge_Sort(int l,int r,int b[]=::b) { static int c[M]; int i,mid=l+r>>1,re=0; if(l==r) return 0; re=Merge_Sort(l,mid,b)+Merge_Sort(mid+1,r,b); int l1=l,l2=mid+1; for(i=l;i<=r;i++) { if( b[l1]<=b[l2] && l1<=mid || l2>r ) c[i]=b[l1++],re+=l2-mid-1; else c[i]=b[l2++]; } memcpy( b+l , c+l , sizeof(b[0])*(r-l+1) ); return re; } void Update(int c[],int x,int y,int limit) { for(;x<=limit;x+=x&-x) c[x]+=y; } int Get_Ans(int c[],int x) { int re=0; for(;x;x-=x&-x) re+=c[x]; return re; } void Modify(int x,int y) { int i,j,_block=belong[x],temp; for(i=1;i<_block;i++) { temp=upper_bound(b+l[i],b+r[i]+1,y)-upper_bound(b+l[i],b+r[i]+1,a[x]); Update(g[i],_block,-temp,(n-1)/block+1); } for(i=_block+1;(i-1)*block+1<=n;i++) { temp=lower_bound(b+l[i],b+r[i]+1,y)-lower_bound(b+l[i],b+r[i]+1,a[x]); Update(g[_block],i,temp,(n-1)/block+1); } memcpy(b+l[_block],a+l[_block],sizeof(b[0])*(r[_block]-l[_block]+1) ); b[x]=y; temp=Merge_Sort(l[_block],r[_block]); //重构b数组 Update(g[_block],_block,temp-f[_block][_block],(n-1)/block+1); f[_block][_block]=temp; //修改f[i][i]和g[i][~] for(i=_block;(i-1)*block+1<=n;i++) { equals[i][a[x]]--,equals[i][y]++; Update(smaller[i],a[x],-1,n); Update(smaller[i],y,1,n); } //修改euqal和smaller数组 a[x]=y; //修改a数组 } int Query(int x,int y) { static int c[M]; int i,top=0,re=0; if(belong[y]-belong[x]<=1) { memcpy(c+x,a+x,sizeof(a[0])*(y-x+1) ); return Merge_Sort(x,y,c); } for(i=belong[x]+1;i<belong[y];i++) re+=Get_Ans(g[i],belong[y]-1); //BB for(i=x;i<=r[belong[x]];i++) { re+=Get_Ans(smaller[belong[y]-1],a[i])-Get_Ans(smaller[belong[x]],a[i])- ( equals[belong[y]-1][a[i]] - equals[belong[x]][a[i]] ); c[++top]=a[i]; } //AB for(i=l[belong[y]];i<=y;i++) { re+=r[belong[y]-1]-r[belong[x]]- ( Get_Ans(smaller[belong[y]-1],a[i])-Get_Ans(smaller[belong[x]],a[i]) ); c[++top]=a[i]; } //BC return re+Merge_Sort(1,top,c); //AA+AC+CC } int main() { int i,j,k; int p,x,y; cin>>n; for(i=1;i<=n;i++) scanf("%d",&a[i]); block=static_cast<int>(sqrt(n)+1e-7); for(i=1;i<=n;i++) { belong[i]=(i-1)/block+1; b[i]=a[i]; } for(i=1;(i-1)*block+1<=n;i++) { l[i]=(i-1)*block+1,r[i]=min(i*block,n); f[i][i]=Merge_Sort(l[i],r[i]); } //预处理块和f[i][i] for(i=1;(i-1)*block+1<=n;i++) for(j=i+1;(j-1)*block+1<=n;j++) { int p=l[j]; for(k=l[i];k<=r[i];k++) { for(;p<=r[j]&&b[p]<b[k];p++); f[i][j]+=p-l[j]; } } for(i=1;(i-1)*block+1<=n;i++) for(j=i;(j-1)*block+1<=n;j++) Update(g[i],j,f[i][j],(n-1)/block+1); //预处理f数组和g数组 for(i=1;i<=n;i++) for(j=belong[i];j<=(n-1)/block+1;j++) { equals[j][a[i]]++; Update(smaller[j],a[i],1,n); } //预处理equals数组和smaller数组 cin>>m; for(i=1;i<=m;i++) { scanf("%d%d%d",&p,&x,&y); x^=ans;y^=ans; if(p==1) Modify(x,y); else printf("%d\n", ans=Query(x,y) ); } }
时间: 2024-10-10 16:21:06