(原标题有误,写成spaly)
传说是某道国家集训队作业题。
但是,做法相当朴素,只不过是离线回答的。
事实再次证明,离线在大多数情况下优于在线,其原因在于可以充分利用已经算出的答案进行调整。
problem:
题目一
题目描述:
因为小t喜欢吃糖,所以他经常在桌子上摆上一排彩色的糖。每种糖都用一种特殊的颜色标识,而每种颜色我们用数字1、2、3、……表示。现在小t在桌子上摆了n颗糖果。现在小t有困惑了,他想知道从第L颗糖果到第R颗糖果中共有多少种不同的糖果。
YourTask:
帮助小t,完成每一个询问
输入文件:
第一行两个数n、m
第二行n个数ai,表示第i颗糖的颜色
接下来m行每行两个数L、R
输出文件:
m行,对应输入的每一个询问的答案
样例输入:
5 1
1 2 3 4 5
1 5
样例输出:
5
数据约定:
ai <= 10^6
m <= 10^5
n <= 5*10^4
1 <= L <= R <= n
solution:将所有询问读入,以左端点为一关键字,以右端点为二关键字排序,每次根据新增的区间或减少的区间修改答案,y[i]>r是保证右端点递增,方便编程。
另,罗雨屏说,这题或许可用曼哈顿生成树。
再另,时隔多日,罗雨屏再说,利用GSS2的离线思想,预处理找出每个数字的下一个位置,将每个数字第一次出现的位置标为一,原问题转化为在一段区间内统计1的个数(线段树)。
当扫过一个数字,则将该数字下一个位置零改为一。完虐标程裸做。于是这道题我得再写一遍。
var n,m,l,r,tot,i:longint;
d,a:array[0..50000]of longint;
ans,x,y,z:array[1..100000]of longint;
c:array[1..100000]of boolean;
procedure qsort(l,r:longint);
var i,j,x1,y1,c:longint;
begin
i:=l;j:=r;x1:=x[(l+r)>>1];y1:=y[(l+r)>>1];
repeat
while (x[i]<x1)or((x[i]=x1)and(y[i]<y1)) do inc(i);
while (x1<x[j])or((x1=x[j])and(y1<y[j])) do dec(j);
if not(i>j) then begin
c:=x[i];x[i]:=x[j];x[j]:=c;
c:=y[i];y[i]:=y[j];y[j]:=c;
c:=z[i];z[i]:=z[j];z[j]:=c;
inc(i);dec(j)
end
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j)
end;
procedure work(x,y:longint);
//var i:longint;
begin
for i:=l to x-1 do begin
dec(d[a[i]]);
if d[a[i]]=0 then dec(tot)
end;
for i:=r+1 to y do begin
inc(d[a[i]]);
if d[a[i]]=1 then inc(tot)
end;
l:=x;r:=y
end;
procedure doit;
var i:longint;
check:boolean;
begin
check:=true;
fillchar(c,sizeof(c),true);
while check do begin
check:=false;
l:=1;r:=0;tot:=0;
fillchar(d,sizeof(d),0);
for i:=1 to m do
if (c[i])and(y[i]>r) then begin
work(x[i],y[i]);ans[z[i]]:=tot;c[i]:=false;
check:=true
end
end;
end;
procedure init;
var i,xx,j:longint;
begin
readln(n,m);
for i:=1 to n do read(a[i]);
for i:=1 to m do begin readln(x[i],y[i]);z[i]:=i end;
qsort(1,m);
doit;
for i:=1 to m do writeln(ans[i])
end;
begin
assign(input,'sequence.in');reset(input);
assign(output,'sequence.out');rewrite(output);
init;
close(input);close(output)
end.
新发,线段树版,速度超快
uses math;
var n,mm,m1,m:longint;
d:array[1..131072]of longint;
l,r,q,ans,p,a:array[1..100000]of longint;
v:array[0..1000000]of longint;
procedure inf;
begin
assign(input,'sequence.in');reset(input);
assign(output,'sequence.out');rewrite(output)
end;
procedure ouf;
begin
close(input);close(output)
end;
procedure qsort(ll,rr:longint);
var i,j,x,c:longint;
begin
i:=ll;j:=rr;x:=l[(ll+rr)>>1];
repeat
while l[i]<x do inc(i);
while x<l[j] do dec(j);
if not(i>j) then begin
c:=l[i];l[i]:=l[j];l[j]:=c;
c:=r[i];r[i]:=r[j];r[j]:=c;
c:=q[i];q[i]:=q[j];q[j]:=c;
inc(i);dec(j)
end
until i>j;
if i<rr then qsort(i,rr);
if ll<j then qsort(ll,j)
end;
procedure origin;
begin
m1:=1;
while m1<=mm+2 do m1:=m1<<1;m1:=m1+1
end;
procedure change(x,w:longint);
begin
if x=0 then exit;
d[x+m1]:=w;x:=(x+m1)>>1;
while x<>0 do begin
inc(d[x],w);
x:=x>>1
end
end;
function ask(l,r:longint):longint;
begin
l:=l+m1-1;r:=r+m1+1;ask:=0;
while not(l xor r=1) do begin
if l and 1=0 then ask:=ask+d[l+1];
if r and 1=1 then ask:=ask+d[r-1];
l:=l>>1;r:=r>>1
end
end;
procedure init;
var i,j:longint;
begin
readln(n,m);
for i:=1 to n do read(a[i]);readln;
fillchar(v,sizeof(v),0);
mm:=0;
for i:=n downto 1 do begin
p[i]:=v[a[i]];
v[a[i]]:=i;
mm:=max(mm,a[i])
end;
origin;
for i:=0 to mm do
if v[i]<>0 then change(v[i],1);
for i:=1 to m do begin
readln(l[i],r[i]);
q[i]:=i
end;
qsort(1,m);
j:=1;
for i:=1 to n do begin
while l[j]=i do begin
ans[q[j]]:=ask(l[j],r[j]);
inc(j)
end;
change(p[i],1)
end;
for i:=1 to m do writeln(ans[i])
end;
begin
inf;
init;
ouf
end.