CodeForces - 1539F Strange Array(线段树区间合并)
題目鏈接:點擊查看
題目大意:給出一個長度為 nnn 的序列,規定位置 iii 的貢獻是:設 x=a[i]x=a[i]x=a[i],選擇一個包含 iii 的區間 [l,r][l,r][l,r],將其中的數排序后,使得中位數和 xxx 之間的距離的最大值。題目要求輸出 nnn 個位置的答案
題目分析:
設 xxx 為中位數,將大于 xxx 的位置視為 111,小于 xxx 的位置視為 ?1-1?1 ,然后求最長連續子段和,是解決中位數問題經典模型。
對于本題而言,假設只需要詢問一個位置的話,可以從該位置向左向右擴展,找連續子段和最大、最小的位置。換言之我們需要查找從某個位置向左向右的最大、最小連續子段和
那么問題的瓶頸就變成了,對于不同的位置,如何快速修改并維護貢獻呢
其實不難看出,我們并不需要在計算完 i?1i-1i?1 的答案后立馬去計算位置 iii 的答案
所以呢?我們可以對權值進行排序,這樣維護整個數列就變得很簡單了
而計算上文中提到的“從某個位置向左向右的最大、最小連續子段和”,正是前幾日藍橋杯國賽的那個括號序列原題。。線段樹區間合并一下就可以了,查詢的時候可以直接返回結構體,也可以返回數值,無非是 O(nlogn)O(nlogn)O(nlogn) 和 O(nlog2n)O(nlog^2n)O(nlog2n) 的區別罷了
代碼:
// Problem: F. Strange Array // Contest: Codeforces - Codeforces Round #727 (Div. 2) // URL: https://codeforces.com/contest/1539/problem/F // Memory Limit: 256 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) x&-x using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=2e5+100; int n,ans[N]; vector<int>node[N]; struct Node {int l,r,lmax,rmax,lmin,rmin,sum; }tree[N<<2]; Node zero={0,0,0,0,0,0,0}; void change(int k,int x) {tree[k].lmax=tree[k].rmax=tree[k].lmin=tree[k].rmin=tree[k].sum=x; } Node merge(Node a,Node b) {Node ans;ans.l=a.l,ans.r=b.r;ans.sum=a.sum+b.sum;ans.lmax=max(a.lmax,a.sum+b.lmax);ans.lmin=min(a.lmin,a.sum+b.lmin);ans.rmin=min(b.rmin,b.sum+a.rmin);ans.rmax=max(b.rmax,b.sum+a.rmax);return ans; } void build(int k,int l,int r) {tree[k].l=l,tree[k].r=r;if(l==r) {change(k,1);return;}int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);tree[k]=merge(tree[k<<1],tree[k<<1|1]); } void update(int k,int pos) {if(tree[k].l==tree[k].r) {change(k,-1);return;}int mid=(tree[k].l+tree[k].r)>>1;if(pos<=mid) {update(k<<1,pos);} else {update(k<<1|1,pos);}tree[k]=merge(tree[k<<1],tree[k<<1|1]); } Node query(int k,int l,int r) {if(l>r) {return zero;}if(tree[k].l>r||tree[k].r<l) {return zero;} if(tree[k].l>=l&&tree[k].r<=r) {return tree[k];}return merge(query(k<<1,l,r),query(k<<1|1,l,r)); } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);read(n);build(1,1,n);for(int i=1;i<=n;i++) {int x;read(x);node[x].push_back(i);}for(int i=1;i<=n;i++) {for(auto p:node[i]) {update(1,p);}for(auto p:node[i]) {Node l=query(1,1,p-1),r=query(1,p+1,n);int lmin=min(l.rmin,0);int rmin=min(r.lmin,0);int lmax=max(l.rmax,0);int rmax=max(r.rmin,0);ans[p]=max({ans[p],(lmax+rmax+1)/2,(-lmin-rmin)/2});}}build(1,1,n);for(int i=n;i>=1;i--) {for(auto p:node[i]) {update(1,p);}for(auto p:node[i]) {Node l=query(1,1,p-1),r=query(1,p+1,n);int lmin=min(l.rmin,0);int rmin=min(r.lmin,0);int lmax=max(l.rmax,0);int rmax=max(r.rmin,0);ans[p]=max({ans[p],(lmax+rmax)/2,(-lmin-rmin+1)/2});}}for(int i=1;i<=n;i++) {printf("%d ",ans[i]);}return 0; } 超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的CodeForces - 1539F Strange Array(线段树区间合并)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1537E2
- 下一篇: CodeForces - 1547F A