您的位置:首页 > 其它

[jzoj]1341. 失眠(线段树+转化不等式)

2017-04-21 18:17 253 查看

Link:

https://jzoj.net/senior/#main/show/1341

Problem:

对于一个长度为N的序列A,求其中满足两条件i<j<k且Ai<Ak<Aj的(i,j,k)的三元组数目.

Data constraint:

对于20%的数据,有N<=100

对于40%的数据,有N<=1000

对于60%的数据,有N<=100000

对于100%的数据,有N<=200000,A[1..n]∈1..n

Solution:

因为A[1..n]∈1..n,所以不需离散化,直接考虑线段树.

对于这两个限制,看上去很棘手,似乎怎么做都不可,但实际上我们只需把条件变化一下即可.

我们只需求出满足i<j<k,Ai<Aj,Ak的三元组对数再减去i<j<k,Ai<Aj<Ak的三元组对数即为i<j<k,Ai<Ak<Aj的三元组对数了.

维护两颗线段树即可.

Code:

const
maxn=200000;
var
f:array[1..maxn*10] of int64;
f1,f2:array[1..maxn*10] of int64;
a:array[1..maxn] of int64;
n,j,x,ans,s1,s2,xx:int64;
i:longint;
procedure find(x,st,en,l,r:longint);
var
mid:longint;
begin
if (st=l) and (en=r) then
inc(xx,f[x])
else
begin
mid:=(st+en) shr 1;

if mid>=r then find(x shl 1,st,mid,l,r) else
if mid<l then find(x shl 1+1,mid+1,en,l,r) else
begin
find(x shl 1,st,mid,l,mid);
find(x shl 1+1,mid+1,en,mid+1,r);
end;
end;
end;
procedure modify(x,st,en,w:longint);
var
mid:longint;
begin
if (st=en) then inc(f[x]) else
begin
mid:=(st+en) shr 1;

if mid>=w then modify(x shl 1,st,mid,w) else modify(x shl 1+1,mid+1,en,w);

f[x]:=f[x shl 1]+f[x shl 1+1];
end;
end;

function max(x,y:longint):longint;
begin
if x>y then exit(x) else exit(y);
end;

procedure update1(x,st,en,l,r,w:longint);
var
mid:longint;
begin
if (st=l) and (en=r) then
inc(f1[x],w)
else
begin
mid:=(st+en) shr 1;

if mid>=r then update1(x shl 1,st,mid,l,r,w) else
if mid<l then update1(x shl 1+1,mid+1,en,l,r,w) else
begin
update1(x shl 1,st,mid,l,mid,w);
update1(x shl 1+1,mid+1,en,mid+1,r,w);
end;

f1[x]:=f1[x shl 1]+f1[x shl 1+1];
end;
end;
procedure find1(x,st,en,l,r:longint);
var
mid:longint;
begin
if (st=l) and (en=r) then s1:=s1+f1[x] else
begin
mid:=(st+en) shr 1;

if mid>=r then find1(x shl 1,st,mid,l,r) else
if mid<l then find1(x shl 1+1,mid+1,en,l,r) else
begin
find1(x shl 1,st,mid,l,mid);
find1(x shl 1+1,mid+1,en,mid+1,r);
end;
end;
end;

procedure update2(x,st,en,l,r,w:longint);
var
mid:longint;
begin
if (st=l) and (en=r) then
inc(f2[x],w)
else
begin
mid:=(st+en) shr 1;

if mid>=r then update2(x shl 1,st,mid,l,r,w) else
if mid<l then update2(x shl 1+1,mid+1,en,l,r,w) else
begin
update2(x shl 1,st,mid,l,mid,w);
update2(x shl 1+1,mid+1,en,mid+1,r,w);
end;

f2[x]:=f2[x shl 1]+f2[x shl 1+1];
end;
end;
procedure find2(x,st,en,l,r:longint);
var
mid:longint;
begin
if (st=l) and (en=r) then s2:=s2+f2[x]
else
begin
mid:=(st+en) shr 1;

if mid>=r then find2(x shl 1,st,mid,l,r) else
if mid<l then find2(x shl 1+1,mid+1,en,l,r) else
begin
find2(x shl 1,st,mid,l,mid);
find2(x shl 1+1,mid+1,en,mid+1,r);
end;
end;
end;

begin
readln(n);
for i:=1 to n do
read(a[i]);

for i:=n downto 1 do
begin
xx:=0;
if a[i]<n then find(1,1,n,a[i]+1,n);
inc(ans,xx*(xx-1) div 2);

modify(1,1,n,a[i]);
end;

for i:=1 to n do
update2(1,1,n,a[i],a[i],1);

for i:=1 to n do
begin
s1:=0;
if a[i]>1 then find1(1,1,n,1,a[i]-1);
s2:=0;
if a[i]<n then find2(1,1,n,a[i]+1,n);

update1(1,1,n,a[i],a[i],1);
update2(1,1,n,a[i],a[i],-1);

dec(ans,s1*s2);
end;

writeln(ans);
end.


总结

在一些看似简单的题目上,只要稍加改动,很多人就不会做了,其实要掌握的还是举一反三的思想,这样对于同一类的题目才不会犯傻.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: