1260. 三元數對 ★ 輸入檔案: three.in 輸出檔案: three.out 簡單對比
時間限制:1 s 記憶體限制:128 MB 【題目描述】
Chineselyl 最近對一種叫做“三元數對”的東西非常感興趣。在含有 n 個整數的序列 A1,A2,…An 中,三個數被稱作“三元數對”若且唯若i<j<k 且 Ai<Aj<Ak 。現在 Chineselyl 正忙著準備會考呢,他想請你幫忙統計一下一個整數序列中“三元數對”的個數。 【輸入格式】
* 第一行一個整數 n
* 接下來有 N 行,分別表示這個整數序列的每一項 【輸出格式】
* 輸出這個整數序列中三元數對的個數 【範例輸入】
512234
【範例輸出】
7
【輸入輸出範例說明】
這7個三元數對分別是
1 2 31 2 41 2 31 2 41 3 42 3 42 3 4
【資料規模】
30%的資料中 n<=100
60%的資料中 n<=2000
100%的資料中 n<=30000 0<=Ai<=maxlongint
註:大規模資料隨機產生。
這個題很像那個 COGS 859 數列 但是Ai的範圍擴大了 我們只能按n來建樹
維護編號是否存在 查詢有多少比自己編號小的存在
要事先排序來保證資料的遞增/遞減性
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int lim=30011;int sumv[lim<<2];int m,n,a,b,c;struct self{int x,y;}s[lim];long long l[lim],r[lim],z;void pushup(int o){sumv[o]=sumv[o<<1]+sumv[o<<1|1];}int w;int querymin(int o,int l,int r){ if(r<=w)return sumv[o]; int m=(l+r)>>1; int ret=0; if(w>m)ret+=querymin(o<<1|1,m+1,r); ret+=querymin(o<<1,l,m); return ret;}int querymax(int o,int l,int r){ if(l>=w)return sumv[o]; int m=(l+r)>>1; int ret=0; if(w<=m)ret+=querymax(o<<1,l,m); ret+=querymax(o<<1|1,m+1,r); return ret;}void add(int o,int l,int r){ if(l==r) { sumv[o]++; return; } int m=(l+r)>>1; if(w<=m)add(o<<1,l,m); else add(o<<1|1,m+1,r); pushup(o);}int cmp(self a1,self a2){return a1.y<a2.y;}int q[lim],top;int main(){ freopen("three.in","r",stdin); freopen("three.out","w",stdout); scanf("%d",&m); for(a=1;a<=m;a++) { scanf("%d",&s[a].y); s[a].x=a; } sort(s+1,s+m+1,cmp); memset(sumv,0,sizeof(sumv)); for(a=1;a<=m;) {top=0;for(b=a;s[b].y==s[a].y;b++){top++;q[top]=s[b].x;w=s[b].x-1;if(w>=1)l[b]=querymin(1,1,m);else l[b]=0;}a=b;for(b=1;b<=top;b++){w=q[b];add(1,1,m);}} memset(sumv,0,sizeof(sumv)); for(a=m;a>=1;) {top=0;for(b=a;s[b].y==s[a].y;b--){top++;q[top]=s[b].x;w=s[b].x+1;if(w<=m)r[b]=querymax(1,1,m);else r[b]=0;z+=l[b]*r[b];}a=b;for(b=1;b<=top;b++){w=q[b];add(1,1,m);}} cout<<z<<endl; return 0;}