bzoj1878

像我这种蒟蒻这道题从在线算法思考基本毫无思路

但是发现题目中只涉及到询问而不涉及到修改,这类题目一般都是离线算法大概

考虑到这题为什么不能直接区间求值,因为区间中同色点会被重复计算(废话)

下面我们就要通过离线算法来排除区间内同色点干扰

首先想到对询问区间以左端点排序,

考虑到区间内的同色点我们只要算最左边的就行了

先将每种颜色第一次出现的位置标记为1

然后从左往右扫描每一个位置,算出以这个位置为左端点的区间答案(区间和)

然后再将这个位置颜色的下一个同色位置标记

这样我们就保证了每次区间询问,同色点只算了一遍

因为一个区间内要么不存在同色点,

要么同色点只出现了一次(被标记了一次),下一个同色点一定还没有标记,而上一个同色点一定在区间外左侧

语言表述不太好,具体还是看程序吧……

 1 var a,c,next:array[0..60010] of longint;
 2     x,y,ans,p:array[0..200010] of longint;
 3     last:array[0..1000000] of longint;
 4     max,i,n,m,j:longint;
 5 function lowbit(x:longint):longint;
 6   begin
 7     exit(x and(-x));
 8   end;
 9 
10 function sum(x:longint):longint;
11   begin
12     sum:=0;
13     while x<>0 do
14     begin
15       sum:=sum+c[x];
16       x:=x-lowbit(x);
17     end;
18   end;
19 
20 procedure add(x:longint);
21   begin
22     while x<=n do
23     begin
24       inc(c[x]);
25       x:=x+lowbit(x);
26     end;
27   end;
28 
29 procedure swap(var a,b:longint);
30   var c:longint;
31   begin
32     c:=a;
33     a:=b;
34     b:=c;
35   end;
36 
37 procedure sort(l,r: longint);
38   var i,j,z: longint;
39   begin
40     i:=l;
41     j:=r;
42     z:=x[(l+r) div 2];
43     repeat
44       while x[i]<z do inc(i);
45       while z<x[j] do dec(j);
46       if not(i>j) then
47       begin
48         swap(x[i],x[j]);
49         swap(y[i],y[j]);
50         swap(p[i],p[j]);
51         inc(i);
52         dec(j);
53       end;
54     until i>j;
55     if l<j then sort(l,j);
56     if i<r then sort(i,r);
57   end;
58 
59 begin
60   readln(n);
61   for i:=1 to n do
62   begin
63     read(a[i]);
64     if max<a[i] then max:=a[i];
65   end;
66   readln(m);
67   for i:=1 to m do
68   begin
69     readln(x[i],y[i]);
70     p[i]:=i;
71   end;
72   sort(1,m);
73   fillchar(last,sizeof(last),0);
74   for i:=n downto 1 do  //计算每个位置下一个同色点的位置
75   begin
76     next[i]:=last[a[i]];
77     last[a[i]]:=i;
78   end;
79   for i:=1 to max do   //先映射每种颜色第一次出现的位置
80     if last[i]<>0 then add(last[i]);
81 
82   j:=1;
83   for i:=1 to n do
84   begin
85     while x[j]=i do
86     begin
87       ans[p[j]]:=sum(y[j])-sum(x[j]-1);
88       inc(j);
89     end;
90     if next[i]<>0 then add(next[i]);
91   end;
92   for i:=1 to m do
93     writeln(ans[i]);
94 end.
View Code
原文地址:https://www.cnblogs.com/phile/p/4473184.html