[jzoj]1341. 失眠(线段树+转化不等式)
2017-04-21 18:17
253 查看
Link:
https://jzoj.net/senior/#main/show/1341Problem:
对于一个长度为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.
总结
在一些看似简单的题目上,只要稍加改动,很多人就不会做了,其实要掌握的还是举一反三的思想,这样对于同一类的题目才不会犯傻.相关文章推荐
- JZOJ4774 【GDOI2017模拟9.10】子串 线段树合并维护SAM的fail树信息(CF 666E类似)
- [jzoj]3733. 【Usaco2014Open银组】照相(pairphoto) (线段树)
- JZOJ 4920 降雷皇(最长上升子序列、线段树)
- [jzoj]3526. 【NOIP2013模拟11.7A组】不等式(solve)(类欧几里得)
- 【jzoj4845】【寻找】【线段树】
- poj2777--Count Color(线段树,二进制转化)
- 【jzoj5232】【NOIP2017模拟A组模拟8.5】【带权排序】【线段树】
- 【JZOJ3965】【Usaco2014 March Gold】The Lazy Cow(扫描线+线段树)
- zoj 3686 树转化为数组表示,线段树区间更新
- Jzoj4747 被粉碎的线段树
- HDU2795 billboard【转化为线段树。】
- [jzoj]3729. 【NOIP2014模拟7.10】表达式的值(exp) (分块转化模型)
- JZOJ4829. 【GDOI2017模拟10.30】独木桥 根据性质转化模型后二分答案
- 杂 - 数据结构 - 平衡树 - 权值线段树 - JZOJ 100036 随机
- JZOJ 4898 人生的价值(线段树、扫描线)
- JZOJ5419. 【NOIP2017提高A组集训10.24】线段树
- [jzoj]3480. 【NOIP2013模拟联考9】阿Q的停车场(park)(线段树+堆)
- hdu 4533 线段树(问题转化+)
- [dfs序][线段树][并查集] JZOJ P3766 大融合
- [jzoj]4883. 【NOIP2016提高A组集训第12场11.10】灵知的太阳信仰(线段树优化DP)