題意:按順序給定一些人和能量值。問按照順序選人,中間人能量值在兩邊人能量值的中間,問最多有多少種選法
思路:一次ac
有木有!其實是照著書上題解的思路打的。
設c[i]
為某a[i]
處左邊能量值比他小的人數和,
d[i]
為右邊能量值比他大的人數和,然後乙個簡單公式即可。關鍵是怎樣快速的求c[i]。
以a[i]
值建樹狀陣列,其中
c[i]
從前往後,
d[i]
從後往前(小創新,和書上不一樣雖然換湯不換藥),設存在的點
x[a[i]] = 1,
然後用不斷更新陣列的方式得到每個點的
c[i]
,d[i]
值。本題要求每個人能量值不重複,如果重複的話
x[i]
多加值就好。
不看知識點根本做不出來好嘛!其實可以這樣想:如何求前乙個區間和後乙個區間的數值和,除了線段樹,就是樹狀陣列了!
原始碼:#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int const maxn = 100000+5;
int a[maxn],c[maxn],d[maxn],x[maxn],sum[maxn];
int n,mmax,tmax;
ll res;
int gmax(int a,int b)
void init()
memset(c,0,sizeof(c));
memset(d,0,sizeof(d));
memset(x,0,sizeof(x));
memset(sum,0,sizeof(sum));
tmax = mmax = res = 0;
int lowbit(int l)
return l&-l;
int les(int aa)
int ans = 0;
// printf("at first , aa = %d\n",aa);
while(aa>0){
// printf("aa = %d\n",aa);
ans += sum[aa];
aa-=lowbit(aa);
return ans;
int big(int aa)
return les(mmax) - les(aa-1);
void add(int aa)
while(aa<=tmax){
sum[aa]+=1;
aa+=lowbit(aa);
void check()
int i;
printf("c = ");
for(i=0; iprintf("%d ",c[i]);
printf("\n d = ");
for(i=0; iprintf("%d ",d[i]);
printf("\n");
int main()
int t;
scanf("%d",&t);
while(t--){
init();
scanf("%d",&n);
for(int i=0; iscanf("%d",&a[i]);
tmax = gmax(tmax,a[i]);
for(int i=0; immax = gmax(mmax,a[i]);
x[a[i]] = 1;
add(a[i]);
c[i] = les(a[i]-1);
// for(int i=1; i<=mmax; i++)
// printf("%d ",sum[i]);
// printf("\n");
mmax = 0;
memset(x,0,sizeof(x));
memset(sum,0,sizeof(sum));
for(int i=n-1; i>=0; i--){
mmax = gmax(mmax,a[i]);
x[a[i]] = 1;
d[i] = big(a[i]+1);
res += (n-i-1-d[i])*(i-c[i])+c[i]*d[i];
add(a[i]);
// check();
printf("%i64d\n",res);
return 0;
樹狀陣列 hdu2492 Ping pong
如果是列舉參加比賽的人,那麼列舉起來就非常的複雜了 如果是列舉裁判,題目會變得簡單很多 假如裁判是第i個人,那麼參加比賽的肯定分別在i的左邊和i的右邊 那麼我就可以統計 1,i 1 這個區間內有多個人的rank小於等於i,i 1,n 這個區間內有多少人的rank大於等於i,兩者相乘,就是左邊小於等於...
HDU 2492 Ping pong 樹狀陣列
題目大意 一條大街上住著 n 個桌球愛好者,經常比賽切磋技術,每個人有乙個不同的技能值ai。每場比賽需要三個人,兩名選手,一名裁判。但是裁判必須住在兩名選手之間,而且裁判的技能值不能小於或小於兩名選手的技能值。問共有多少種比賽。思路 列舉裁判,找出位於裁判前面的比裁判技能小的人數和位於裁判後面技能比...
樹狀陣列POJ2155
poj 2155是一道很不錯的題目,表面上看,這題的要求似乎和樹狀陣列的使用方法恰好相反,改變的是乙個區間,查詢的反而是乙個點。實際上可以通過乙個轉化巧妙的解決。首先對於每個數a定義集合up a 表示 定義集合down a 表示。可以發現對於任何a於是對於這道題目來說,翻轉乙個區間 a,b 為了便於...