[國家集訓隊] 排隊
阿新 • • 發佈:2018-05-08
sig tput 整數 ios 隊列 交換 #define http int
,邊角暴力,塊內統計答案。
如何統計呢?由樓下大佬的公式我們可以知道,如果 \(a[i]<val[l]\) 且 \(a[i]>val[r]\),那麽 \(ans++\)。這是將 \(i\) 從 \(belong[l]+1\) 到 \(belong[r]-1\) 循環。
換個思路,如果 \(i\) 代表的不是元素,而是數值呢?
也就是說,將 \(i\) 從1到值域循環,那麽如果 \(i<val[l]\) 且 \(i>val[r]\),那麽 \(ans\) 就會變大。
變大多少呢?這個值即為 \(sum[belong[r]-1][i]-sum[belong[l]][i]\) 。
其他三種情況同理,那麽每次答案就求完了。
記得更新 \(sum\) 數組!
Luogu
Description
排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一個,我一個,大的分給你,小的留給我,吃完果果唱支歌,大家樂和和。
紅星幼兒園的小朋友們排起了長長地隊伍,準備吃果果。不過因為小朋友們的身高有所區別,排成的隊伍高低錯亂,極不美觀。設第i個小朋友的身高為hi,我們定義一個序列的雜亂程度為:
滿足 \(i<j\) 且 \(h_i>h_j\) 的 \((i,j)\) 數量。
幼兒園阿姨每次會選出兩個小朋友,交換他們的位置,請你幫忙計算出每次交換後,序列的雜亂程度。為方便幼兒園阿姨統計,在未進行任何交換操作時,你也應該輸出該序列的雜亂程度。
Input
第一行為一個正整數n,表示小朋友的數量;
第二行包含n個由空格分隔的正整數h1,h2,…,hn,依次表示初始隊列中小朋友的身高;
第三行為一個正整數m,表示交換操作的次數;
以下m行每行包含兩個正整數ai和bi-,表示交換位置ai與位置bi的小朋友。
Output
輸出文件共m+1行,第i行一個正整數表示交換操作i結束後,序列的雜亂程度。
Range
對於100%的數據,\(1\leq m\leq 2\times 10^3,1\leq n\leq 2\times 10^4,1\leq h_i\leq 10^9,a_i\ne b_i,1\leq a_i,b_i\leq n\)。
Solution
這裏有一種前綴和思想的做法。
這個思想是受作詩的啟發。
在那道題中,我們借用前綴和統計了每個數出現次數,這道題也完全可以嘛!
定義 \(sum[i][j]\) 表示第 \(1-i\) 個塊,身高為 \(j\) 的小孩出現的次數。
所有身高先離散化一遍之後,沒有任何操作的答案先樹狀數組求一下。
然後就可以借助以前的答案更新當前了,這個樓下大佬講了就不啰嗦了。
對於交換 \([l,r]\)
如何統計呢?由樓下大佬的公式我們可以知道,如果 \(a[i]<val[l]\) 且 \(a[i]>val[r]\),那麽 \(ans++\)。這是將 \(i\) 從 \(belong[l]+1\) 到 \(belong[r]-1\) 循環。
換個思路,如果 \(i\) 代表的不是元素,而是數值呢?
也就是說,將 \(i\) 從1到值域循環,那麽如果 \(i<val[l]\) 且 \(i>val[r]\),那麽 \(ans\) 就會變大。
變大多少呢?這個值即為 \(sum[belong[r]-1][i]-sum[belong[l]][i]\)
其他三種情況同理,那麽每次答案就求完了。
記得更新 \(sum\) 數組!
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 20005
#define int long long
int f[N],len;
int n,m,tot,ans;
int sum[150][N];
int val[N],t[N];
int l[150],r[150];
int block,belong[N];
int ask(int x){
int b=0;
for(;x;x-=x&-x)
b+=f[x];
return b;
}
void add(int x){
for(;x<=n;x+=x&-x)
f[x]++;
}
int query(int a,int b){
//printf("a=%lld,b=%lld\n",a,b);
if(val[a]==val[b]) return ans;
if(belong[a]==belong[b] or belong[a]+1==belong[b]){
//puts("dfgfhhg");
for(int i=a+1;i<b;i++){
if(val[i]<val[a]) ans--;
if(val[i]<val[b]) ans++;
if(val[i]>val[a]) ans++;
if(val[i]>val[b]) ans--;
//printf("i=%lld,val=%lld,ans=%lld\n",i,val[i],ans);
}
if(val[a]>val[b]) ans--;
if(val[a]<val[b]) ans++;
if(belong[a]+1==belong[b])
sum[belong[a]][val[a]]--,sum[belong[a]][val[b]]++;
val[a]^=val[b]^=val[a]^=val[b];
return ans;
}
if(val[a]>val[b]) ans--;
if(val[a]<val[b]) ans++;
for(int i=a+1;i<=r[belong[a]];i++){
if(val[i]<val[a]) ans--;
if(val[i]<val[b]) ans++;
if(val[i]>val[a]) ans++;
if(val[i]>val[b]) ans--;
}
for(int i=b-1;i>=l[belong[b]];i--){
if(val[i]<val[a]) ans--;
if(val[i]<val[b]) ans++;
if(val[i]>val[a]) ans++;
if(val[i]>val[b]) ans--;
}
for(int i=1;i<=len;i++){
if(i<val[a]) ans-=sum[belong[b]-1][i]-sum[belong[a]][i];
if(i<val[b]) ans+=sum[belong[b]-1][i]-sum[belong[a]][i];
if(i>val[a]) ans+=sum[belong[b]-1][i]-sum[belong[a]][i];
if(i>val[b]) ans-=sum[belong[b]-1][i]-sum[belong[a]][i];
}
for(int i=belong[a];i<belong[b];i++){
sum[i][val[a]]--;
sum[i][val[b]]++;
}
val[a]^=val[b]^=val[a]^=val[b];
/*for(int i=1;i<=tot;i++){
for(int j=1;j<=len;j++)
printf("i=%lld,j=%lld,sum=%lld\n",i,j,sum[i][j]);
}*/
return ans;
}
void file(){
freopen("in.txt","r",stdin);
freopen("out2.txt","w",stdout);
}
signed main(){
//file();
scanf("%lld",&n);
block=sqrt(n);
tot=n/block;
if(n%block) tot++;
for(int i=1;i<=n;i++)
scanf("%lld",&val[i]),t[i]=val[i],belong[i]=(i-1)/block+1;
std::sort(t+1,t+1+n);
len=std::unique(t+1,t+1+n)-t-1;
for(int i=1;i<=n;i++) val[i]=std::lower_bound(t+1,t+1+len,val[i])-t;
for(int i=1;i<=tot;i++)
l[i]=(i-1)*block+1,r[i]=i*block;
for(int i=n;i;i--){
ans+=ask(val[i]-1);
add(val[i]);
sum[belong[i]][val[i]]++;
}
for(int i=1;i<=tot;i++){
for(int j=1;j<=len;j++)
sum[i][j]+=sum[i-1][j];
}
scanf("%lld",&m);
printf("%lld\n",ans);
while(m--){
int x,y;
scanf("%lld%lld",&x,&y);
if(x>y) x^=y^=x^=y;
printf("%lld\n",query(x,y));
}
return 0;
}
[國家集訓隊] 排隊