Description
很久很以前,有一个古老的村庄——xiba村,村子里生活着n+1个村民,但由于历届村长恐怖而且黑暗的魔法统治下,村民们各自过着独立的生活,完全没有意识到其他n个人的存在。
但有一天,村民xiba臻无意中也得到了魔法,并发现了这个恐怖的事实。为了反抗村长,他走遍了全世界,找到了其他n个村民,并组织他们发动革命。但让这n个素不相识的村民(xiba臻已跟他们认识)同心协力去抵抗村长是很困难的,所以xiba臻决定先让他们互相认识。
这里,xiba臻用了xiba村特有的xiba思维:先让这n个人排成一列,并依次从1-n标号。然后每次xiba臻会选出一个区间[l, r],在这个区间中的人会去认识其他在这个区间中的人,但已经认识过得不会再去认识。这样,进行m次操作后,xiba臻认为这n个人能认识到许多人。
但是,为了精确地知道当前有多少对人已经认识了,xiba臻想要知道每次操作后会新产生出多少对认识的人,但这已是xiba思维无法解决的事了,你能帮帮他吗?
Input
第一行两个整数n,m。
接下来m行每行两个整数li,ri,表示每次操作的区间。
Output
共m行,每行一个整数ans_i,表示第i次操作后新产生出ans_i对认识的人。
Sample Input
5 5
2 3
2 4
3 5
1 5
2 4
Sample Output
1
2
2
5
0
Data Constraint
对于20%的数据,1≤n,m≤100。
对于50%的数据,1≤n,m≤5000。
对于100%的数据,1≤n,m≤300000,1≤li≤ri≤n。
背景:做完这题,真的想说一句我的天。
分析:
20%,纯暴力。
50%,设f[i]为某人i能认识i–f[i]的人,显然这个数组具有单调性。对于每次询问l–r,枚举区间内每个人,因为当前某人i能使前i个人认识,现在有让他与l–i-1的人认识(为不重复,只讨论每个人前面的人),显然增加了f[i]-l个人,统计和,即可。
70%:由于具有单调性,如果f[i]<=l,即已经认识了前面在区间内的所有人,显然对答案无贡献,那后面的点也没有贡献啦。
100%:(正解):用线段树维护全间最大值和区间和,用50%方法即可。
(水解):这个方法不知在各大题库能否过。70%的点是从l–r枚举,变为从r–l枚举,因为数据的问题,倒着枚举会先break掉,不会超时,甚至会比正解快。
代码:
var
i,j,l,r,n,m:longint;
ans:int64;
f:array [1..300001] of longint;
begin
assign(input,'ohmygod.in');
assign(output,'ohmygod.out');
reset(input);
rewrite(output);
readln(n,m);
for i:=1 to n do
f[i]:=i;
for i:=m downto 1 do
begin
readln(l,r);
ans:=0;
for j:=r downto l do
begin
if f[j]>l then
begin
ans:=ans+f[j]-l;
f[j]:=l;
end
else break;
end;
writeln(ans);
end;
close(input);
close(output);
end.
type
cy=record
sum:int64;
lab,max:longint;
end;
const
maxn=300005;
var
n,m,i,j,x,y,z:longint;
a,ans:array[0..maxn]of int64;
tree:array[0..maxn*4]of cy;
function
max(x,y:longint):longint;
begin
if x>y then exit(x)
else exit(y);
end;
procedure
maketree(p,l,r:longint);
var
mid:longint;
begin
if l=r then
begin
tree[p].sum:=a[l];
tree[p].max:=a[l];
tree[p].lab:=0;
exit;
end;
mid:=(l+r)shr 1;
maketree(p<<1,l,mid);
maketree(p<<1+1,mid+1,r);
tree[p].max:=max(tree[p<<1].max,tree[p<<1+1].max);
tree[p].sum:=tree[p<<1].sum+tree[p<<1+1].sum;
end;
procedure
push(x,p,l,r,mid:longint);
begin
tree[p<<1].max:=x;
tree[p<<1].sum:=x*(mid-l+1);
tree[p<<1].lab:=x;
tree[p<<1+1].max:=x;
tree[p<<1+1].sum:=x*(r-mid);
tree[p<<1+1].lab:=x;
tree[p].lab:=0;
end;
function
find(p,l,r,t:longint):longint;
var
mid:longint;
begin
if l=r then exit(l)
else
begin
mid:=(l+r)>>1;
if tree[p].lab<>0 then push(tree[p].lab,p,l,r,mid);
if tree[p<<1].max>t then exit(find(p<<1,l,mid,t))
else exit(find(p<<1+1,mid+1,r,t));
end;
end;
procedure
change(p,l,r,a,b,t:longint);
var
mid:longint;
begin
if (l=a)and(r=b) then
begin
tree[p].max:=t;
tree[p].sum:=t*(b-a+1);
if l<>r then tree[p].lab:=t;
exit;
end;
mid:=(l+r)>>1;
if tree[p].lab<>0 then push(tree[p].lab,p,l,r,mid);
if b<=mid then change(p<<1,l,mid,a,b,t)
else if a>mid then change(p<<1+1,mid+1,r,a,b,t)
else
begin
change(p<<1,l,mid,a,mid,t);
change(p<<1+1,mid+1,r,mid+1,b,t);
end;
tree[p].max:=max(tree[p<<1].max,tree[p<<1+1].max);
tree[p].sum:=tree[p<<1].sum+tree[p<<1+1].sum;
end;
begin
assign(input,'ohmygod.in'); reset(input);
assign(output,'ohmygod.out'); rewrite(output);
readln(n,m);
for i:=1 to n do a[i]:=i;
maketree(1,1,n);
ans[0]:=tree[1].sum;
for i:=1 to m do
begin
readln(x,y);
if tree[1].max<=x then ans[i]:=ans[i-1]
else
begin
if x<>y then
begin
z:=find(1,1,n,x);
if z<=x then change(1,1,n,x,y,x)
else if z>y then ans[i]:=ans[i-1]
else change(1,1,n,z,y,x);
ans[i]:=tree[1].sum;
end
else ans[i]:=ans[i-1];
end;
writeln(ans[i-1]-ans[i]);
end;
close(input); close(output);
end.