标签:amp -- merge printf 复杂度 highlight cond define 区间查询
题意:用如下方法生成一个超长序列:维护一个元素为序列的栈,操作有三种,1.push一个仅含一个数字的序列;2.将栈顶的两个序列合并;3.将栈顶序列重复$k$次后作为新的栈顶,保证操作完后栈中只有一个序列,求这个序列的逆序对数
直接维护整个序列肯定MLE+TLE,考虑只维护一些关键的值,对序列$S$,设$S_x$为序列的逆序对数,$S_y$为$S$对$S$的逆序对数,$S_d$是一个map,存各个元素及其出现次数
$\text{push}(v)$:$S_x=S_y=0,S_d=\{v:1\}$
$\text{repeat}(S,k)$:$S‘_x=kS_x+\binom k2S_y,S_y=k^2S_y$,$S_d$的每个元素出现次数都乘$k$
$\text{merge}(S,T)$:$S‘_x=S_x+T_x+u,S‘_y=S_y+T_y+u+v$,其中$u$为$S$对$T$的逆序对数,$v$为$T$对$S$的逆序对数,最后把$S_d$和$T_d$合并即可
直接暴力做就可以拿$50$分了,因为最慢的地方是合并,考虑优化
用动态开点线段树维护$S_d$,每次合并采用启发式合并的策略:在较小的$S_d$中枚举元素,在$T_d$中区间查询得到$u,v$,再用启发式合并将$S_d,T_d$合并即可(线段树合并也可以,不过不会降低时间复杂度)
全局乘$k$维护一个标记即可
#include<stdio.h> #include<map> using namespace std; typedef long long ll; const int mod=1000000007,mx=100000; int mul(int a,int b){return(ll)a*b%mod;} void inc(int&a,int b){(a+=b)%=mod;} int pow(int a,int b){ int s=1; while(b){ if(b&1)s=mul(s,a); a=mul(a,a); b>>=1; } return s; } struct seg{ int l,r,s; }t[20000010]; int M; void modify(int p,int v,int l,int r,int&x){ if(x==0)x=++M; inc(t[x].s,v); if(l==r)return; int mid=(l+r)>>1; if(p<=mid) modify(p,v,l,mid,t[x].l); else modify(p,v,mid+1,r,t[x].r); } int query(int L,int R,int l,int r,int x){ if(L>R||x==0)return 0; if(L<=l&&r<=R)return t[x].s; int mid=(l+r)>>1,s=0; if(L<=mid)inc(s,query(L,R,l,mid,t[x].l)); if(mid<R)inc(s,query(L,R,mid+1,r,t[x].r)); return s; } map<int,int>::iterator it; struct seq{ int x,y,rt,l; map<int,int>s; void operator=(int v){ x=y=0; l=1; s.clear(); s[v]=1; rt=0; modify(v,1,1,mx,rt); } void operator*=(int k){ x=(mul(k,x)+mul((ll)k*(k-1)/2%mod,y))%mod; y=mul(mul(k,k),y); l=mul(l,k); } void operator+=(seq&b){ int u,v; u=v=0; #define id it->first #define val it->second #define inv(x) pow(x,mod-2) if(s.size()>b.s.size()){ for(it=b.s.begin();it!=b.s.end();it++){ inc(u,mul(val,query(id+1,mx,1,mx,rt))); inc(v,mul(val,query(1,id-1,1,mx,rt))); } for(it=b.s.begin();it!=b.s.end();it++){ val=mul(val,mul(b.l,inv(l))); modify(id,val,1,mx,rt); inc(s[id],val); } }else{ for(it=s.begin();it!=s.end();it++){ inc(u,mul(val,query(1,id-1,1,mx,b.rt))); inc(v,mul(val,query(id+1,mx,1,mx,b.rt))); } for(it=s.begin();it!=s.end();it++){ val=mul(val,mul(l,inv(b.l))); modify(id,val,1,mx,b.rt); inc(b.s[id],val); } s.swap(b.s); swap(rt,b.rt); swap(l,b.l); } u=mul(u,mul(l,b.l)); v=mul(v,mul(l,b.l)); x=((ll)x+b.x+u)%mod; y=((ll)y+b.y+u+v)%mod; } }p[100010]; int main(){ int n,M,x; M=0; scanf("%d",&n); while(n--){ scanf("%d",&x); if(x>0)p[++M]=x; if(x==0){ M--; p[M]+=p[M+1]; } if(x<0)p[M]*=-x; } for(M--;M;M--)p[M]+=p[M+1]; printf("%d\n",p[1].x); }
标签:amp -- merge printf 复杂度 highlight cond define 区间查询
原文地址:https://www.cnblogs.com/jefflyy/p/9859967.html