[题目描述]
众所周知,lyp喜欢以用各种方式折磨别人为乐,这次,他趁 wars不在时在他的电脑上
挂了一把神奇的锁,这把锁需要一串巨长无比的数字密码才可以解开,这 个密码由 lyp 自
己保管,这样 wars 就没法 Kingdom Rush 了。但 wars 设法从 lyp 的脑袋中挖出了有关密码
的信息,这些信息是一列非负整数{An}。而解开密 码锁的方式是首先输入这列这数的逆序
对数,而后依次会在 wars的电脑屏幕上显示两个数字 p,q,你则需要输入将整数列中第 p个
整数替换成q后整个数列的逆序 对数,这样的询问会有 m个。当然,这样的替换只对这一
次的询问有效。现在 wars急着去打Kingdom Rush,因此将打开电脑的任务交给了你。
[数据范围]
n<=50000,m<=50000
0<=序列的每一元素(包括询问中的)<=100000
保证询问合法。
[题解]
这道题目可以用离线算法做.将询问排序后就可以用一个树状数组搞出来了.
由于解决这道问题要牵扯到查询区间内某一范围内的数的个数,所以也可以用函数式线段树(不过常数被树状数组完爆).总之,这还是一道不错的函数式线段树基础题的.
讲一下函数式的思想:由于线段树每次修改只要改log(n)个节点,所以每次新建log(n)个节点即可.因为每次root都会被更新,所以直接开一个数组记住每次的root,查询时直接自顶向下的查询即可.
图就不画了(太丑了),不过这东西实现起来还是比较容易的,代码也不长.唯一的缺点是需要的空间太多了.
Code:
program lyp;
type int=longint;
const null=-1;
var
i,j,k,m,ans,n,tot,x,y:int;
s,ls,rs,ll,rr:array[0..2000000]of int;
root,a:array[0..50000]of int;
function build(l,r:int):int;var mid,now:int;
begin
if l=r-1 then begin
inc(tot);ls[tot]:=null;rs[tot]:=null;ll[tot]:=l;rr[tot]:=r;
exit(tot);
end;
mid:=(l+r)>>1;
inc(tot);now:=tot;
ll[tot]:=l;rr[tot]:=r;
ls[now]:=build(l,mid);
rs[now]:=build(mid,r);
exit(now);
end;
function ins(x,y:int):int;var mid:int;
begin
if ll[x]=rr[x]-1 then begin
inc(tot);s[tot]:=s[x]+1;
ls[tot]:=null;rs[tot]:=null;
ll[tot]:=ll[x];rr[tot]:=rr[x];
exit(tot);
end;
if ll[x]>=rr[x] then exit;
mid:=(ll[x]+rr[x])>>1;
inc(tot);ins:=tot;
ls[tot]:=ls[x];rs[tot]:=rs[x];
ll[tot]:=ll[x];rr[tot]:=rr[x];
if y>mid then rs[ins]:=ins(rs[x],y)
else ls[ins]:=ins(ls[x],y);
s[ins]:=s[ls[ins]]+s[rs[ins]];
end;
function ask(r1,r2,l,r:int):int;var mid:int;
begin
if(r1=r2)then exit(0);
if(l<=ll[r1])and(rr[r1]<=r)then exit(s[r2]-s[r1]);
ask:=0;mid:=(ll[r1]+rr[r1])>>1;
if(r>mid)then ask:=ask+ask(rs[r1],rs[r2],l,r);
if(l<mid)then ask:=ask+ask(ls[r1],ls[r2],l,r);
end;
begin
assign(input,'lyp.in');reset(input);
assign(output,'lyp.out');rewrite(output);
root[0]:=build(0,100000);
read(n,m);
for i:=1 to n do begin
read(a[i]);
inc(a[i]);
root[i]:=ins(root[i-1],a[i]);
ans:=ans+ask(root[0],root[i],a[i],100000);
end;
writeln(ans);
for i:=1 to m do begin
read(x,y);inc(y);
if y>a[x]then k:=-ask(root[0],root[x-1],a[x],y)+ask(root[x],root[n],a[x]-1,y-1)
else k:=ask(root[0],root[x-1],y,a[x])-ask(root[x],root[n],y-1,a[x]-1);
writeln(ans+k);
end;
close(input);close(output);
end.
BY QW
转载请注明出处