这道题是目前我做bzoj最感动的一题没有之一……
首先先警示一下,分块的题目能不套主席树尽量不套
因为主席树不仅回答来一个log而且常数也比较大,对于分块这种根号的算法非常不适合
这里是求区间逆序对,考虑查询,不难想到答案是[l,r]所夹整块之间的逆序对数目和两边的数所带来的逆序对数目和
首先第一部分是可以预处理出来的,算法是O(n*tot*logn)
第二部分裸的想法是求每个数ai在区间[l,i]比它小的个数,然后可以用主席树搞搞
但是不幸的是,这样直接T到死,自测bzoj第一点的数据就跑了24s……伤不起
所以考虑bzoj2724的做法,我们还是先预处理f[i,j],g[i,j]表示1~i块内比j大的数和比j小的数的个数
考虑两边的数ai,令它构成一个序列bj,这些数所带来的逆序对数目就是
如果ai在整块左边,就是=[l,r]所夹整块内比它小的数个数,在整块右边就是=[l,r]所夹整块内比它大的数个数
最后再加上bj序列的逆序对数目就是答案
考虑一种快速计算逆序对的算法,不难想到用树状数组,这已经相当优
下面就是令人感动的事情了,用树状数组替代主席树之后,程序已经能跑到28s左右
想办法干掉fillchar并在调整一下块的大小,优化到了23,24s左右
然后始终没能跑进20s……然后我就各种想,突然发现
当l正好是一个块的左端点时,我的程序仍然遍历了l所在的块(很多分块的程序都是这样),其实可以没必要
加了这个优化本地正好跑了20s,激动了,然后试着把r正好是块的右端点也特判一下
王苍啊,终于过了,在bzoj上跑了18s……
出题人大概是故意卡常数的吧……
有幸成为这道题第一个pascal通过者,非常感动(苦逼的pascal伤不起啊)
附上丑陋的代码:
1 const maxn=50000; 2 3 var s:array[0..300,0..300] of longint; 4 f,g:array[0..300,0..maxn] of longint; 5 co,v,a,be,b,c,rank,h:array[0..maxn] of longint; 6 time,i,size,n,m,j,k,ans,x,y,t,tot,p:longint; 7 8 function lowbit(x:longint):longint; 9 begin 10 exit(x and (-x)); 11 end; 12 13 function min(a,b:longint):longint; 14 begin 15 if a>b then exit(b) else exit(a); 16 end; 17 18 procedure swap(var a,b:longint); 19 var c:longint; 20 begin 21 c:=a; 22 a:=b; 23 b:=c; 24 end; 25 26 procedure add(x:longint); 27 begin 28 while x<=p do 29 begin 30 if v[x]<>time then 31 begin 32 c[x]:=0; 33 v[x]:=time; 34 end; 35 inc(c[x]); 36 x:=x+lowbit(x); 37 end; 38 end; 39 40 function ask(x:longint):longint; 41 begin 42 ask:=0; 43 while x>0 do 44 begin 45 if v[x]<>time then //为了不用fillchar加了一个时间戳 46 begin 47 c[x]:=0; 48 v[x]:=time; 49 end; 50 ask:=ask+c[x]; 51 x:=x-lowbit(x); 52 end; 53 end; 54 55 procedure sort(l,r: longint); 56 var i,j,x,y: longint; 57 begin 58 i:=l; 59 j:=r; 60 x:=b[(l+r) shr 1]; 61 repeat 62 while b[i]<x do inc(i); 63 while x<b[j] do dec(j); 64 if not(i>j) then 65 begin 66 swap(b[i],b[j]); 67 swap(h[i],h[j]); 68 inc(i); 69 j:=j-1; 70 end; 71 until i>j; 72 if l<j then sort(l,j); 73 if i<r then sort(i,r); 74 end; 75 76 function getans(l,r:longint):longint; 77 var i,j,x:longint; 78 begin 79 getans:=0; 80 t:=0; 81 if be[r]=be[l] then 82 begin 83 for i:=l to r do 84 begin 85 getans:=getans+t-ask(rank[i]); 86 add(rank[i]); 87 inc(t); 88 end; 89 end 90 else begin 91 x:=min(be[r]*size,n); 92 if ((be[l]-1)*size+1=l) and (x=r) then exit(s[be[l],be[r]]) //正好是端点可以直接计算 93 else if ((be[l]-1)*size+1=l) then 94 begin 95 getans:=getans+s[be[l],be[r]-1]; 96 for i:=(be[r]-1)*size+1 to r do 97 begin 98 x:=rank[i]; 99 getans:=getans+f[be[r]-1,x]-f[be[l]-1,x]; 100 getans:=getans+t-ask(x); 101 add(x); 102 inc(t); 103 end; 104 exit; 105 end 106 else if (x=r) then 107 begin 108 getans:=getans+s[be[l]+1,be[r]]; 109 for i:=l to be[l]*size do 110 begin 111 x:=rank[i]; 112 getans:=getans+g[be[r],x]-g[be[l],x]; 113 getans:=getans+t-ask(x); 114 add(x); 115 inc(t); 116 end; 117 exit; 118 end; 119 getans:=getans+s[be[l]+1,be[r]-1]; 120 for i:=l to be[l]*size do 121 begin 122 x:=rank[i]; 123 getans:=getans+g[be[r]-1,x]-g[be[l],x]; 124 getans:=getans+t-ask(x); //为了只调用一次查询 125 add(x); 126 inc(t); 127 end; 128 for i:=(be[r]-1)*size+1 to r do 129 begin 130 x:=rank[i]; 131 getans:=getans+f[be[r]-1,x]-f[be[l],x]; 132 getans:=getans+t-ask(x); 133 add(x); 134 inc(t); 135 end; 136 end; 137 end; 138 139 begin 140 readln(n); 141 size:=trunc(sqrt(n)/1.1); 142 for i:=1 to n do 143 begin 144 read(a[i]); 145 b[i]:=a[i]; 146 h[i]:=i; 147 be[i]:=(i-1) div size+1; 148 end; 149 tot:=i div size; 150 if i mod size<>0 then inc(tot); 151 sort(1,n); 152 p:=1; 153 rank[h[1]]:=1; 154 for i:=2 to n do 155 begin 156 if b[i]<>b[i-1] then inc(p); 157 rank[h[i]]:=p; 158 end; 159 for i:=1 to tot do //预处理f[i,j],g[i,j] 160 begin 161 x:=min(i*size,n); 162 for j:=(i-1)*size+1 to x do 163 inc(co[rank[j]]); 164 f[i,p]:=0; 165 for j:=p-1 downto 1 do 166 f[i,j]:=f[i,j+1]+co[j+1]; 167 g[i,1]:=0; 168 for j:=2 to p do 169 g[i,j]:=g[i,j-1]+co[j-1]; 170 end; 171 for i:=1 to tot do //预处理i~j块内的逆序对数 172 begin 173 t:=0; 174 inc(time); 175 for j:=(i-1)*size+1 to n do 176 begin 177 x:=t-ask(rank[j]); 178 inc(s[i,be[j]],x); 179 add(rank[j]); 180 inc(t); 181 end; 182 for j:=i+1 to tot do 183 s[i,j]:=s[i,j]+s[i,j-1]; 184 end; 185 ans:=0; 186 readln(m); 187 for i:=1 to m do 188 begin 189 inc(time); 190 readln(x,y); 191 x:=x xor ans; 192 y:=y xor ans; 193 if x>y then swap(x,y); 194 ans:=getans(x,y); 195 writeln(ans); 196 end; 197 end.