标签: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