vijos 1459 车展
一个空的树.. 依次添加1到n。就能解决左端点为1的所有询问了吧。然后从2开始做一遍啊...n方logn得到全部答案。”神牛的话就是这么吊……看上去没什么信息量但还是水很深……实际上要维护子树内元素和。也就是我程序里面写的change,lsum指左子树中所有点的值得和,rsum指右子树中所有点的值得和,zsum指整个子树中节点的和,也就是lsum+rsum+本节点的值。在计算代价的时候是这样的……假设从i加到j需到的代价为sum,首先找到中间值,就是排名为(j-i)div2+1的点l,然后在sum上加上“这个节点左子树上的点的总和与这个节点的值*左子树节点个数的绝对值”,由于后者要比前者大……所以就是key[l]*s[left[l]]。右子树就是反过来。但是sum的值还不止这些,还需要在递归的时候加上一些值,即如果这个点是左儿子,那sum就要加上他爹和他右兄弟上所有点的值与他爹和他右兄弟上所有点数*这个key[l]的值,就是rsum[t]+key[t]-(s[right[t]]+1)*l,如果是右子树也是一样……这样就没了。最后注意,一定要开int64,因为这个错误,wa了3次……
const maxn=4000; var key,s,left,right,a:array[0..maxn] of longint; lsum,rsum,zsum:array[0..maxn]of int64; tt,i,j,k,l,n,m,t:longint; f:array[0..2000,0..2000]of int64; sum:int64; procedure change(t:longint); begin lsum[t]:=zsum[left[t]]; rsum[t]:=zsum[right[t]]; zsum[t]:=lsum[t]+rsum[t]+key[t]; end; procedure right_rotate(var t:longint); var k:longint; begin k:=left[t]; left[t]:=right[k]; right[k]:=t; s[k]:=s[t]; s[t]:=s[left[t]]+s[right[t]]+1; change(t); change(k); t:=k; end; procedure left_rotate(var t:longint); var k:longint; begin k:=right[t]; right[t]:=left[k]; left[k]:=t; s[k]:=s[t]; s[t]:=s[left[t]]+s[right[t]]+1; change(t); change(k); t:=k; end; procedure maintain(var t:longint;flag:boolean); begin if flag=false then if s[left[left[t]]]>s[right[t]] then right_rotate(t) else if s[right[left[t]]]>s[right[t]] then begin left_rotate(left[t]); right_rotate(t); end else exit else if s[right[right[t]]]>s[left[t]] then left_rotate(t) else if s[left[right[t]]]>s[left[t]] then begin right_rotate(right[t]); left_rotate(t); end else exit; maintain(left[t],false); maintain(right[t],true); maintain(t,true); maintain(t,false); end; procedure insert(var t,v:longint); begin if t=0 then begin inc(tt); t:=tt; key[t]:=v; s[t]:=1; left[t]:=0; right[t]:=0; lsum[t]:=0; rsum[t]:=0; zsum[t]:=key[t]; end else begin inc(s[t]); if v<key[t] then begin insert(left[t],v); inc(lsum[t],v); inc(zsum[t],v); end else begin insert(right[t],v); inc(rsum[t],v); inc(zsum[t],v); end; maintain(t,v>=key[t]); end; end; function select(var t:longint;k:longint):longint; var l:longint; begin if k=s[left[t]]+1 then begin l:=key[t]; sum:=s[left[t]]*l-lsum[t]+rsum[t]-s[right[t]]*l; exit(key[t]); end else if k<=s[left[t]] then begin l:=select(left[t],k); sum:=sum+rsum[t]+key[t]-(s[right[t]]+1)*l; exit(l) end else begin l:=select(right[t],k-1-s[left[t]]); sum:=sum+(s[left[t]]+1)*l-key[t]-lsum[t]; exit(l); end; end; begin readln(n,m); for i:=1 to n do read(a[i]); for i:=1 to n do f[i,i]:=0; for i:=1 to n-1 do begin fillchar(left,sizeof(left),0); fillchar(s,sizeof(s),0); fillchar(right,sizeof(right),0); fillchar(lsum,sizeof(lsum),0); fillchar(rsum,sizeof(rsum),0); fillchar(zsum,sizeof(zsum),0); fillchar(key,sizeof(key),0); //傻逼又没有必要的初始化,去掉也行啦…… tt:=0; t:=0; insert(t,a[i]); for j:=i+1 to n do begin insert(t,a[j]); sum:=0; k:=select(t,(j-i)div 2+1); f[i,j]:=sum; end; end; sum:=0; for i:=1 to m do begin readln(j,k); sum:=sum+f[j,k]; end; writeln(sum); end.