傳送門
文章目錄
題意:
給你一個長度為nnn的數(shù)組,對每個位置iii求一個最大價值,價值計(jì)算方式如下:選擇一個包含iii的[l,r][l,r][l,r],讓后將其拿出來排序,之后價值就是當(dāng)前位置的值aia_iai?在排序后的位置到中位數(shù)的位置的距離,如果有相同的值位置可以任意安排,中位數(shù)的位置定義為:如果長度為奇數(shù)位置就是l+r2\frac{l+r}{2}2l+r?,否則l+r+12\frac{l+r+1}{2}2l+r+1?。
思路:
對于每個位置,我們可以想到分兩種情況貪心,一種是讓≤ai\le a_i≤ai?的盡可能多,另一種是讓≥ai\ge a_i≥ai?的盡可能多,我們只討論第一種,就是讓≤ai\le a_i≤ai?的盡可能多。
在確定aia_iai?之后就有一個比較套路的做法了,我們可以將>ai>a_i>ai?的都設(shè)為?1-1?1,≤ai\le a_i≤ai?的都設(shè)為111,這樣我們就可以從[i+1,n][i+1,n][i+1,n]找一個值最大的前綴,從[1,i?1][1,i-1][1,i?1]找一個值最大的后綴,讓后二者結(jié)合起來為sumsumsum,答案就是sum2\frac{sum}{2}2sum?。現(xiàn)在問題就轉(zhuǎn)換成如何快速求最長前綴和最長后綴了。
這也是一個經(jīng)典問題,將其放在線段樹上,維護(hù)個lmax,rmax,sumlmax,rmax,sumlmax,rmax,sum即可。
目前我們這個問題已經(jīng)解決了一半了,現(xiàn)在是如何將≤ai\le a_i≤ai?的都賦為111,>ai>a_i>ai?的賦為?1-1?1呢?我們不能每次都暴力修改,考慮將每個值對應(yīng)的ididid都放在一個桶里,初始的時候讓每個位置都為?1-1?1,讓后從[1,n][1,n][1,n]遍歷這個桶,每次將當(dāng)前桶內(nèi)的ididid位置都變成111即可,這樣放在桶里就可以很好的解決這個問題了。
對于另一種情況,他的答案應(yīng)該為sum+12\frac{sum+1}{2}2sum+1?,這個跟中位數(shù)的位置有關(guān)系,偶數(shù)的話中位數(shù)是靠近右邊的內(nèi)個數(shù),所以如果sumsumsum表示的是≥ai\ge a_i≥ai?的個數(shù)的話,那么aia_iai?在最左邊,所以要上取整。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=200010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
,m
;
int ans
[N
];
struct node
{int val
,id
;bool operator < (const node
&W
) const {return val
<W
.val
;}
}a
[N
];
vector
<node
>v
[N
];
struct Node
{int l
,r
;int sum
,smax
,lmax
,rmax
;
}tr
[N
*4];void pushup(Node
&a
,Node
&l
,Node
&r
)
{a
.sum
=l
.sum
+r
.sum
;a
.lmax
=max(l
.lmax
,l
.sum
+r
.lmax
);a
.rmax
=max(r
.rmax
,r
.sum
+l
.rmax
);
}void pushup(int u
)
{pushup(tr
[u
],tr
[u
<<1],tr
[u
<<1|1]);
}void build(int u
,int l
,int r
,int c
)
{if(l
==r
) {tr
[u
]={l
,r
,c
,c
,c
,c
};return;}tr
[u
].l
=l
,tr
[u
].r
=r
;int mid
=(tr
[u
].l
+tr
[u
].r
)>>1;build(u
<<1,l
,mid
,c
),build(u
<<1|1,mid
+1,r
,c
);pushup(u
);
}void modify(int u
,int x
,int c
)
{if(tr
[u
].l
==x
&&tr
[u
].r
==x
) tr
[u
]={x
,x
,c
,c
,c
,c
};else{int mid
=(tr
[u
].l
+tr
[u
].r
)>>1;if(x
<=mid
) modify(u
<<1,x
,c
);else modify(u
<<1|1,x
,c
);pushup(u
);}
}Node
query(int u
,int l
,int r
)
{if(l
>r
) return {0,0,0,0,0,0};if(tr
[u
].l
>=l
&&tr
[u
].r
<=r
) return tr
[u
];int mid
=(tr
[u
].l
+tr
[u
].r
)>>1;if(r
<=mid
) return query(u
<<1,l
,r
);else if(l
>mid
) return query(u
<<1|1,l
,r
);else {Node a
,b
,ans
;a
=query(u
<<1,l
,r
);b
=query(u
<<1|1,l
,r
);pushup(ans
,a
,b
);return ans
;}
}int main()
{cin
>>n
;for(int i
=1;i
<=n
;i
++) {scanf("%d",&a
[i
].val
);a
[i
].id
=i
;v
[a
[i
].val
].pb(a
[i
]);}build(1,1,n
,-1);for(int i
=1;i
<=n
;i
++) {for(auto x
:v
[i
]) modify(1,x
.id
,1);for(auto x
:v
[i
]) {Node r
=query(1,x
.id
+1,n
),l
=query(1,1,x
.id
-1);ans
[x
.id
]=max(ans
[x
.id
],(l
.rmax
)/2);ans
[x
.id
]=max(ans
[x
.id
],(r
.lmax
)/2);ans
[x
.id
]=max(ans
[x
.id
],(l
.rmax
+r
.lmax
)/2);}}build(1,1,n
,-1);for(int i
=n
;i
>=1;i
--) {for(auto x
:v
[i
]) modify(1,x
.id
,1);for(auto x
:v
[i
]) {Node r
=query(1,x
.id
+1,n
),l
=query(1,1,x
.id
-1);ans
[x
.id
]=max(ans
[x
.id
],(l
.rmax
+1)/2);ans
[x
.id
]=max(ans
[x
.id
],(r
.lmax
+1)/2);ans
[x
.id
]=max(ans
[x
.id
],(l
.rmax
+r
.lmax
+1)/2);}}for(int i
=1;i
<=n
;i
++) printf("%d ",ans
[i
]); puts("");return 0;
}
總結(jié)
以上是生活随笔為你收集整理的Codeforces Round #727 (Div. 2) F. Strange Array 线段树 + 区间合并 + 排序优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。