这里有个sb写这道题写了一下午。
首先来考虑一段子段上的答案,显然答案有一个区间,设最大值为\(E\),则最小值一定在\([E,E+\log n]\)之间。
我们考虑按照最大值分段,最优秀的状态应该是最后合并成若干个\(E\),然后直接对这些\(E\)归并起来就是答案,但是最大值分出来的段可能不是这么凑巧,但是实际上如果合并不出来\(E\)可以当成一个\(E\)来看,因为最优秀的合并一定不会有两个不是\(E\)的相邻,而这样的话在合并时和\(E\)没什么区别。
这样我们基本上可以得到一个策略,先按照最大值分段,然后每段内计算出合并成\(E\)的最少的数量,设总个数为\(p\),则这个子段的答案为\(\lceil \log p\rceil\)。
建立笛卡尔树,然后对这个过程分治。每次从孩子节点合并出左子树和右子树合并成啥样,然后再根据当前的权值进行进一步合并。
然后是统计答案,我们枚举答案和\(E\)的增量,然后统计答案至少为\(E+\delta\)的区间个数,这样也可以得到权值和。枚举这个权值后可以枚举较小一边的点,然后去计算有多少个右端点合法即可。
但你实际上写出来会有一点问题。
1.在合并某个子树内的值的时候,因为总删除次数只有\(n\)次,因此直接暴力删即可。
2.在统计答案的时候,我们取的最小值其实不是两个待合并的最小值,而是分开来的最小值,因此不能简单地用启发式合并的方式证明复杂度。但是我们注意到它们对应的原序列上的长度是相同的,而对原序列启发式合并的复杂度是\(O(n\log n)\),因此这个低于原序列合并复杂度。可以认为是\(O(n\log^2n)\)的。
3.在合并左右子树的时候发现合并不能改变相对顺序。因此简单的vector
无法解决。我们考虑用这样的一种方式合并:
初始化vector具有\(x\)个空位与在此之后的\(x\)个值。每次合并,如果后面的大小小于前面的,那么直接将后面的合并到前面即可。如果前面的小于后面的,那么就将前面的值填入后面的空位中,如果空位不足直接重构。
后面一部分发现如果重构那么大小至少变成两倍,因此总复杂度\(O(n\log n)\),且可以\(O(1)\)查询。
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=(1<<18)+5,M=N*4+5,K=1e5+5,mod=1e9+7,Mod=mod-1,INF=2e9+7;const db eps=1e-5;
int n,A[N],L[N],R[N],st[N],H,Rt,lg[N*2],Si[N],Ph;ll Ans;
struct Node{int x,w,id;Node operator +(const Node &B)const{return (Node){max(x,B.x)+1,w+B.w,id};};}Cl,P[N];
#define CL(A) A.clear(),A.shrink_to_fit()
struct Ques{
vector<Node> Ts;int H;Node find(int x){return x+H>=Ts.size()?Cl:Ts[x+H];}
void CG(int w){
while(Ts.size()-H>1&&max(Ts[H].x,Ts[H+1].x)<w) {Ph=-1;for(int i=H;i<Ts.size();i++) (i-H)&1?(P[Ph]=P[Ph]+Ts[i]):(P[++Ph]=Ts[i]);
CL(Ts);for(int i=0;i<=Ph;i++) Ts.PB(Cl);for(int i=0;i<=Ph;i++) Ts.PB(P[i]);H=Ph+1;
}
}
void Mg(Ques &B){
if(Ts.size()-H>B.Ts.size()-B.H) {for(int i=B.H;i<B.Ts.size();i++) Ts.PB(B.Ts[i]);CL(B.Ts);return;}
if(Ts.size()-H<=B.H){for(int i=Ts.size()-1;i>=H;i--) B.Ts[--B.H]=Ts[i];swap(B.Ts,Ts);H=B.H;CL(B.Ts);return;}
int i;Ph=-1;for(i=H;i<Ts.size();i++) P[++Ph]=Ts[i];for(i=B.H;i<B.Ts.size();i++) P[++Ph]=B.Ts[i];CL(Ts);for(i=0;i<=Ph;i++) Ts.PB(Cl);for(i=0;i<=Ph;i++) Ts.PB(P[i]);CL(B.Ts);H=Ph+1;
}
}S1[N],S2[N];
void dfs(int x){if(!x) return;dfs(L[x]);dfs(R[x]);int i,j;Si[x]=Si[L[x]]+Si[R[x]]+1;S1[L[x]].CG(A[x]);S1[R[x]].CG(A[x]);S2[L[x]].CG(A[x]);S2[R[x]].CG(A[x]);
S1[x].Ts.PB((Node){A[x],1,x});S2[x].Ts.PB((Node){A[x],1,x});
S1[x].Mg(S1[R[x]]);S1[R[x]]=S1[0];S2[x].Mg(S2[L[x]]);S2[L[x]]=S2[0];
Ans+=1ll*(Si[L[x]]+1)*(Si[R[x]]+1)*A[x];
//cerr<<x<<' '<<Ans<<'\n';for(Node p:S1[x]) cerr<<p.w<<' ';cerr<<'\n';for(Node p:S2[x]) cerr<<p.w<<' ';cerr<<'\n';
for(i=0;i<=lg[S1[x].Ts.size()+S2[x].Ts.size()-S1[x].H-S2[x].H];/*cerr<<Ans<<'\n',*/i++) {
if(S1[x].Ts.size()-S1[x].H<S2[x].Ts.size()-S2[x].H)for(j=0;j<S1[x].Ts.size()-S1[x].H;j++) Ans+=1ll*S1[x].find(j).w*(max((1<<i)-j,0)+S2[x].H>=S2[x].Ts.size()?0:S2[x].find(max(0,(1<<i)-j)).id-(x-Si[L[x]])+1)/*,cerr<<S2[x].find(max(0,(1<<i)-j)).id<<' '<<x-Si[L[x]]<<' '<<Ans<<'\n'*/;
else for(j=0;j<S2[x].Ts.size()-S2[x].H;j++) Ans+=1ll*S2[x].find(j).w*(max((1<<i)-j,0)+S1[x].H>=S1[x].Ts.size()?0:x+Si[R[x]]+1-S1[x].find(max(0,(1<<i)-j)).id);
}
// for(Node i:S1[x]) S1[L[x]].PB(i);swap(S1[L[x]],S1[x]);S1[L[x]].clear();S1[L[x]].shrink_to_fit();for(Node i:S2[x]) S2[R[x]].PB(i);swap(S2[R[x]],S2[x]);S2[R[x]].clear();S2[R[x]].shrink_to_fit();
S1[L[x]].Mg(S1[x]);swap(S1[L[x]],S1[x]);S1[L[x]]=S1[n+1];S2[R[x]].Mg(S2[x]);swap(S2[R[x]],S2[x]);S2[R[x]]=S2[n+1];if(x%100==0) cerr<<x<<'\n';
}
int main(){
freopen("1.in","r",stdin);
int i;scanf("%d",&n);A[0]=1e9;for(i=1;i<=n;i++){scanf("%d",&A[i]);while(A[st[H]]<A[i]) H--;L[i]=R[st[H]];R[st[H]]=i;st[++H]=i;}Rt=R[0];
for(i=2;i<=2*n+1;i++) lg[i]=((1<<lg[i-1])==i-1?lg[i-1]+1:lg[i-1]);dfs(Rt);printf("%lld\n",Ans);
}
标签:int,luogu,P8275,合并,Ts,using,Revisited,size,define
From: https://www.cnblogs.com/275307894a/p/16821941.html