[Ynoi2019模拟赛]Yuno loves sqrt technology I
作者:互联网
题目描述
给你一个长为n的排列,m次询问,每次查询一个区间的逆序对数,强制在线。
题解
MD不卡了。。TMD一点都卡不动。
强制在线的话也没啥好一点的方法,只能分块预处理了。
对于每个块,我们设lef[i]表示i到这个i这个元素所在块的块头的区间逆序对,rig[i]表示到块尾的逆序对。
在设一个cnt[i][j]表示从第i个块到第j个块的逆序对。
然后考虑如何处理询问。
整块之间的可以直接O(1)取答案,对于散块,我们需要求出散块内部的答案,散块对整块的答案,散块对散块的答案。
对于散块内的,因为散块在当前块中一定是它的前缀或后缀,所以我们直接O(1)取答案。
对于散块对整块的,我们可以在维护一个tag[i][j]表示前i个块,大于/小于j的元素有多少个,然后询问就扫描散块,前缀和统计即可。
对于散块对散块的,可以在每个块内维护元素的相对大小,然后对于两个不相交的区间,可以用桶排+扫描求出逆序对。
但还有一个特殊情况,就是lr在同一个块里,前面的方法不是很实用。
我们设当前块头尾h,那么答案可以表示为ans(h-r)-ans(h-l)-ans(h~l,l~r),前两个部分已经求过了,后面的用桶排+扫描即可。
不过常数略大,开2s应该能过(用了CAT的IO优化都不行。。)。
代码
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize ("Ofast") #pragma GCC optimize ("Ofast","inline","unroll-loops") #pragma GCC optimize ("no-stack-protector") #include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <cassert> #include <cmath> #define RG register #define set_file(FinlineE) freopen(FinlineE ".in", "r", stdin), freopen(FinlineE ".out", "w", stdout) #define close_file() fclose(stdin), fclose(stdout) #define For(i, a, b) for(RG int i = a, ___u = b; i <= ___u; ++i) #define ForDown(i, a, b) for(RG int i = b, ___d = a; i >= ___d; --i) #define cmax(i, j) ((i) < (j) ? (i) = (j) : (i)) #define cmin(i, j) ((i) > (j) ? (i) = (j) : (i)) #define dmax(i, j) ((j) < (i) ? (i) : (j)) #define dmin(i, j) ((i) < (j) ? (i) : (j)) #define ddel(i, j) ((i) > (j) ? (i) - (j) : (j) - (i)) #define dabs(i) ((i) > 0 ? (i) : -(i)) #define dsqr(x) ((x) * (x)) #define lowbit(i) ((i) & -(i)) using namespace std; #define N 100002 #define M 340 typedef long long ll; int n,m,tr[N],mis[M],rnk[N],n1,ji[M],be[N],a[N],b[M],lef[N],tag1[M][N],tag2[M][N],rig[N]; int q[N],pos[N]; ll ans,cnt[M][M]; namespace io { const int MAXBUF = 1 << 20; const int OUTPUT = 1 << 23; char B[MAXBUF], *S = B, *T = B; #define getc() (S == T && (T = (S = B) + fread(B, 1, MAXBUF, stdin), S == T) ? 0 : *S++) #define fastcall __attribute__((optimize("-O3"))) #define inline __inline__ __attribute__((always_inline)) template<class Type> inline Type read() { RG Type aa = 0; RG bool bb = 0; RG char ch, *S = io::S, *T = io::T; for(ch = getc(); (ch < '0' || ch > '9') && ch != '-'; ch = getc()) ; for(ch == '-' ? bb = 1 : aa = ch - '0', ch = getc(); '0' <= ch && ch <= '9'; ch = getc()) aa += (aa << 3) + aa + ch - '0'; io::S = S, io::T = T; return bb ? -aa : aa; } int (*F)() = read<int>; char buff[OUTPUT], *iter = buff; template<class T>inline void P(RG T x, RG char ch = '\n') { ///*lgg*/cout << x << ch; return; static int stack[110]; RG int O = 0; RG char *iter = io::iter; if(!x)*iter++ = '0'; else { (x < 0) ? x = -x, *iter++ = '-' : 1; for(; x; x /= 10) stack[++O] = x % 10; for(; O; *iter++ = '0' + stack[O--]) ; } *iter++ = ch, io::iter = iter; } inline void puts(RG const char *s) {while(*s) *iter++ = *s++;} inline void output() {fwrite(buff, 1, iter - buff, stdout), iter = buff;} } inline void add(int x,int y){while(x<=n)tr[x]+=y,x+=x&-x;} inline int query(int x){int ans=0;while(x)ans+=tr[x],x-=x&-x;return ans;} inline int merge(int l2,int r2,int l1,int r1){ int ans=0; for(int i=l1;i<=r1;++i)ji[rnk[i]]=a[i]; q[0]=0; for(int i=1;i<=n1;++i)if(ji[i]){ q[++q[0]]=ji[i];ji[i]=0; } int p=0; for(int i=l2;i<=r2;++i)ji[rnk[i]]=a[i]; for(int i=1;i<=n1;++i)if(ji[i]){ while(p<=q[0]&&(!p||q[p]<=ji[i]))p++;p--; ans+=p;ji[i]=0; } return ans; } int main(){ freopen("in","r",stdin); freopen("out","w",stdout); RG int (*F)() = io::read<int>; n=F();m=F(); n1=sqrt(n); for(int i=1;i<=n;++i)a[i]=F(),be[i]=(i-1)/n1+1,pos[a[i]]=i; for(int i=1;i<=be[n];++i){ int l=(i-1)*n1+1,r=min(n,i*n1);int top=0; for(int j=l;j<=r;++j)b[++top]=a[j]; sort(b+1,b+top+1); for(int j=1;j<=top;++j)rnk[pos[b[j]]]=j; for(int j=l;j<=r;++j){ lef[j]=query(n-a[j]+1); if(j!=l)lef[j]+=lef[j-1]; add(n-a[j]+1,1); } for(int j=1;j<=n;++j)tag2[i][j]=tag2[i-1][j]+query(n-j+1); for(int j=l;j<=r;++j)add(n-a[j]+1,-1); for(int j=r;j>=l;--j){ rig[j]=query(a[j]); if(j!=r)rig[j]+=rig[j+1]; add(a[j],1); } for(int j=1;j<=n;++j)tag1[i][j]=tag1[i-1][j]+query(j); for(int j=l;j<=r;++j)add(a[j],-1); } for(int i=1;i<be[n];++i){ for(int j=(i-1)*n1+1;j<=i*n1;++j)add(n-a[j]+1,1); cnt[i][i]=lef[i*n1]; for(int j=i+1;j<=be[n];++j){ cnt[i][j]=cnt[i][j-1];int x=min(n,n1*j); for(int k=(j-1)*n1+1;k<=x;++k){ cnt[i][j]+=query(n-a[k]+1); add(n-a[k]+1,1); } } for(int j=(i-1)*n1+1;j<=n;++j)add(n-a[j]+1,-1); } int l,r; while(m--){ l=F();r=F();l^=ans;r^=ans; if(l>r)l^=r^=l^=r;ans=0; if(r>n||l<1){ans=0;puts("0");continue;} if(be[l]==be[r]){ ans=lef[r];if(l!=(be[l]-1)*n1+1)ans-=lef[l-1],ans-=merge((be[l]-1)*n1+1,l-1,l,r); } else{ int st=be[l]+1,en=be[r]-1; for(int i=l;i<=be[l]*n1;++i)ans=ans+tag1[en][a[i]]-tag1[st-1][a[i]]; for(int i=en*n1+1;i<=r;++i)ans=ans+tag2[en][a[i]]-tag2[st-1][a[i]]; ans+=cnt[st][en]+rig[l]+lef[r]; ans+=merge(l,(st-1)*n1,en*n1+1,r); } io::P(ans); } io::output(); close_file(); return 0; }
标签:Ynoi2019,ch,int,sqrt,RG,loves,include,散块,define 来源: https://www.cnblogs.com/ZH-comld/p/10449396.html