bzoj 1878 SDOI2009树状数组 离线操作
本来想写2120的,结果想起来了这个
我们先对于询问左端点排序,用树状数组存区间字母个数,对于每种字母,
第一次出现的位置记录为1,剩下的记录为0,然后记录下,每种颜色
后面第一个和他相同颜色的位置
然后扫询问,对于一个询问直接输出区间和,然后假设当前询问是
l1,r1,下一询问是,l2,r2,我们把l1到l2区间内的每个位置颜色的后一颜色
赋值成1,然后继续处理下个询问就好了。
/************************************************************** Problem: 1878 User: BLADEVIL Language: Pascal Result: Accepted Time:3260 ms Memory:29524 kb ****************************************************************/ //By BLADEVIL var n, m :longint; a :array[0..50010] of longint; l, r :array[0..200010] of longint; other :array[0..50010] of longint; last, first :array[0..1000010] of longint; num, ans :array[0..1000010] of longint; c :array[0..3000010] of longint; tot :longint; procedure swap(var a,b:longint); var c :longint; begin c:=a; a:=b; b:=c; end; procedure qs(low,high:longint); var i, j, x :longint; begin i:=low; j:=high; x:=l[(i+j) div 2]; while i<j do begin while l[i]<x do inc(i); while l[j]>x do dec(j); if i<=j then begin swap(l[i],l[j]); swap(r[i],r[j]); swap(num[i],num[j]); inc(i); dec(j); end; end; if i<high then qs(i,high); if j>low then qs(low,j); end; procedure qs1(low,high:longint); var i, j, x :longint; begin i:=low; j:=high; x:=num[(i+j) div 2]; while i<j do begin while num[i]<x do inc(i); while num[j]>x do dec(j); if i<=j then begin swap(l[i],l[j]); swap(r[i],r[j]); swap(num[i],num[j]); swap(ans[i],ans[j]); inc(i); dec(j); end; end; if i<high then qs1(i,high); if j>low then qs1(low,j); end; procedure init; var i :longint; begin read(n); for i:=1 to n do begin read(a[i]); if tot<a[i] then tot:=a[i]; end; read(m); for i:=1 to m do read(l[i],r[i]); for i:=1 to m do num[i]:=i; qs(1,m); for i:=1 to n do if last[a[i]]<>0 then begin other[last[a[i]]]:=i; last[a[i]]:=i; end else begin last[a[i]]:=i; first[a[i]]:=i; end; end; procedure add(x:longint); begin while x<=n do begin c[x]:=c[x]+1; x:=x+(x and (-x)); end; end; function ask(x:longint):longint; begin ask:=0; while x>0 do begin ask:=ask+c[x]; x:=x-(x and (-x)); end; end; procedure main; var i, j :longint; ll :longint; begin for i:=1 to tot do if first[i]<>0 then add(first[i]); ll:=1; for i:=1 to m do begin for j:=ll to l[i]-1 do if other[j]<>0 then add(other[j]); ans[i]:=ask(r[i])-ask(l[i]-1); ll:=l[i]; end; qs1(1,m); for i:=1 to m do writeln(ans[i]); end; begin init; main; end.