bzoj 2038 莫队算法
莫队算法,具体的可以看10年莫涛的论文。
大题思路就是假设对于区间l,r我们有了一个答案,那么对于区间l,r+1,我们
可以暴力的转移一个答案,那么对于区间l1,r1和区间l2,r2,需要暴力处理
的部分就是|r1-r2|+|l1-l2|如果将l看成x,r看成r,得到的暴力部分就是manhattan距离
那么我们将所有的询问,构成一张二维图,可以从一个点转移到另一个点,且总manhattan距离
尽可能的小,所以可以建立一颗manhattan mst,这样的话就可以得到最优的转移,但是实际来说
搞定一个manhattan mst需要的时间不小,我们可以不要最优解,将询问按l分块,只需要做到在每个
块中尽可能的优就行了,所以每个块中可以根据r排序,然后搞就行了
经莫队证明,这个算法的复杂度上界大概是o(n^1.5)
/************************************************************** Problem: 2038 User: BLADEVIL Language: Pascal Result: Accepted Time:3164 ms Memory:2572 kb ****************************************************************/ //By BLADEVIL type rec =record l, r, w, s :longint; end; var n, m :longint; c, size :array[0..50010] of int64; len :longint; a :array[0..50010] of rec; now :longint; col, ans :array[0..50010] of int64; all, num :int64; procedure swap(var a,b:longint); var c :longint; begin c:=a; a:=b; b:=c; end; procedure swap_rec(var a,b:rec); var c :rec; begin c:=a; a:=b; b:=c; end; function gcd(a,b:int64):int64; begin if a<b then exit(gcd(b,a)) else if b=0 then exit(a) else exit(gcd(b,a mod b)); end; procedure qs(low,high:longint); var i, j, xx, yy :longint; begin i:=low; j:=high; xx:=a[(i+j) div 2].w; yy:=a[(i+j) div 2].r; while i<j do begin while (a[i].w<xx) or (a[i].w=xx) and (a[i].r<yy) do inc(i); while (a[j].w>xx) or (a[j].w=xx) and (a[j].r>yy) do dec(j); if i<=j then begin swap_rec(a[i],a[j]); inc(i); dec(j); end; end; if i<high then qs(i,high); if j>low then qs(low,j); end; procedure init; var i :longint; begin read(n,m); for i:=1 to n do read(c[i]); len:=trunc(sqrt(m)); for i:=1 to m do begin read(a[i].l,a[i].r); if a[i].l>a[i].r then swap(a[i].l,a[i].r); size[i]:=a[i].r-a[i].l+1; a[i].w:=a[i].l div len+1; a[i].s:=i; end; qs(1,m); end; procedure main; var i, j :longint; begin i:=1; while i<=m do begin now:=a[i].w; fillchar(col,sizeof(col),0); for j:=a[i].l to a[i].r do begin ans[a[i].s]:=ans[a[i].s]+2*(col[c[j]]); col[c[j]]:=col[c[j]]+1; end; inc(i); while a[i].w<=now do begin ans[a[i].s]:=ans[a[i-1].s]; for j:=a[i-1].r+1 to a[i].r do begin ans[a[i].s]:=ans[a[i].s]+2*(col[c[j]]); col[c[j]]:=col[c[j]]+1; end; if a[i-1].l<a[i].l then begin for j:=a[i-1].l to a[i].l-1 do begin col[c[j]]:=col[c[j]]-1; ans[a[i].s]:=ans[a[i].s]-2*col[c[j]]; end; end else for j:=a[i].l to a[i-1].l-1 do begin ans[a[i].s]:=ans[a[i].s]+2*(col[c[j]]); col[c[j]]:=col[c[j]]+1; end; inc(i); if i>m then break; end; end; for i:=1 to m do begin if size[i]=1 then all:=1 else all:=size[i]*(size[i]-1); num:=gcd(ans[i],all); writeln(ans[i] div num,'/',all div num); end; end; begin init; main; end.