4889: [Tjoi2017]不勤劳的图书管理员 树套树

时间:2024-04-29 00:27:55

国际惯例的题面(Bzoj没有,洛谷找的):
4889: [Tjoi2017]不勤劳的图书管理员 树套树
动态加权逆序对,一眼树套树。
256MB内存,5e4范围,不虚不虚。
首先把交换改成两个插入和两个删除。
考虑插入和删除的贡献,就是统计前面比这个值大的数的数值和,数量和,后面比这个值小的数的数值和,数量和。然后特判一下当前两个值构成逆序对的情况即可(因为这种情况会被计算两遍)。
考虑树状数组套动态开点线段树维护这个东西,线段树只需要单点修改区间求和即可,十分简单。
然而数组开不下啊......理论上我们数组范围要开到2e7左右,然而并跑不满,开到1.4e7就足以AC啦。
(但是跑得奇慢无比,怕不是人傻自带大常数)

代码(话说两个log差不多是根号,我这是两个log还有4倍的常数,大概已经比根号慢了):

 #include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long int lli;
const int maxn=5e4+1e2,maxe=1.4e7+1e2;
const int mod=1e9+; int in[maxn],seq[maxn],n; struct SegmentTree {
int lson[maxe],rson[maxe],sum[maxe],siz[maxe],cnt;
inline void insert(int &pos,int l,int r,const int &tar,const int &x,const int &d) {
if( !pos ) pos = ++cnt;
sum[pos] = ( sum[pos] + x ) % mod , siz[pos] += d;
if( l == r ) return;
const int mid = ( l + r ) >> ;
if( tar <= mid ) insert(lson[pos],l,mid,tar,x,d);
else insert(rson[pos],mid+,r,tar,x,d);
}
inline int querysum(int pos,int l,int r,const int &ll,const int &rr) {
if( !pos || ( ll <= l && r <= rr ) ) return sum[pos];
const int mid = ( l + r ) >> ;
if( rr <= mid ) return querysum(lson[pos],l,mid,ll,rr);
else if( ll > mid ) return querysum(rson[pos],mid+,r,ll,rr);
return ( querysum(lson[pos],l,mid,ll,rr) + querysum(rson[pos],mid+,r,ll,rr) ) % mod;
}
inline int querysiz(int pos,int l,int r,const int &ll,const int &rr) {
if( !pos || ( ll <= l && r <= rr ) ) return siz[pos];
const int mid = ( l + r ) >> ;
if( rr <= mid ) return querysiz(lson[pos],l,mid,ll,rr);
else if( ll > mid ) return querysiz(rson[pos],mid+,r,ll,rr);
return ( querysiz(lson[pos],l,mid,ll,rr) + querysiz(rson[pos],mid+,r,ll,rr) ) % mod;
}
}sgt; struct BinaryIndexTree {
int root[maxn],id;
#define lowbit(x) (x&-x)
inline void update(int x,const int &y,const int &val,const int &vs) {
while( x <= n ) sgt.insert(root[x],,n,y,val,vs) , x += lowbit(x);
}
inline int querysum(int x,const int &ll,const int &rr) {
int ret = ;
while(x) ret = ( ret + sgt.querysum(root[x],,n,ll,rr) ) % mod , x -= lowbit(x);
return ret;
}
inline int querysiz(int x,const int &ll,const int &rr) {
int ret = ;
while(x) ret = ( ret + sgt.querysiz(root[x],,n,ll,rr) ) % mod , x -= lowbit(x);
return ret;
}
}bit; inline int segsum(const int &l,const int &r,const int &ll,const int &rr) {
return ( bit.querysum(r,ll,rr) - bit.querysum(l-,ll,rr) + mod ) % mod;
}
inline int segsiz(const int &l,const int &r,const int &ll,const int &rr) {
return ( bit.querysiz(r,ll,rr) - bit.querysiz(l-,ll,rr) + mod ) % mod;
} int main() {
static int m;
static lli now;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",seq+i) , scanf("%d",in+seq[i]);
for(int i=;i<=n;i++) {
now = ( now + bit.querysum(i,seq[i]+,n) ) % mod , now = ( now + (lli) bit.querysiz(i,seq[i]+,n) * in[seq[i]] % mod ) % mod;
bit.update(i,seq[i],in[seq[i]],);
}
for(int i=,a,b;i<=m;i++) {
scanf("%d%d",&a,&b);
if( a > b ) std::swap(a,b);
if( a == b ) {
printf("%lld\n",now);
continue;
}
now -= segsum(,a-,seq[a]+,n) + segsum(a+,n,,seq[a]-) , now -= (lli) in[seq[a]] * ( segsiz(,a-,seq[a]+,n) + segsiz(a+,n,,seq[a]-) ) % mod , now = ( now % mod + mod ) % mod;
now -= segsum(,b-,seq[b]+,n) + segsum(b+,n,,seq[b]-) , now -= (lli) in[seq[b]] * ( segsiz(,b-,seq[b]+,n) + segsiz(b+,n,,seq[b]-) ) % mod , now = ( now % mod + mod ) % mod;
bit.update(b,seq[b],mod-in[seq[b]],-) , bit.update(a,seq[a],mod-in[seq[a]],-);
if( seq[a] > seq[b] ) now = ( now + in[seq[a]] + in[seq[b]] ) % mod; // it have been subed two times .
std::swap(seq[a],seq[b]);
bit.update(a,seq[a],in[seq[a]],) , bit.update(b,seq[b],in[seq[b]],);
now += segsum(,a-,seq[a]+,n) + segsum(a+,n,,seq[a]-) , now += (lli) in[seq[a]] * ( segsiz(,a-,seq[a]+,n) + segsiz(a+,n,,seq[a]-) ) % mod , now = ( now % mod + mod ) % mod;
now += segsum(,b-,seq[b]+,n) + segsum(b+,n,,seq[b]-) , now += (lli) in[seq[b]] * ( segsiz(,b-,seq[b]+,n) + segsiz(b+,n,,seq[b]-) ) % mod , now = ( now % mod + mod ) % mod;
if( seq[a] > seq[b] ) now = ( now - in[seq[a]] - in[seq[b]] + mod ) % mod; // it have been added two times .
printf("%lld\n",now);
}
return ;
}

(另外我为什么又在刷水题了!)

空に舞う雪はまるで白い花びら ひらひら 風に吹かれて散よ
在茫茫天空飞舞着 好似纯白花朵的雪花 迎风飘洒
Ah…染めあげて 消えて無くなるのなら この寂しさも一緒に溶けてゆけ
啊…全都染上純白 如果那些色彩渐渐消失不见的话 那也让这寂寞溶于一起消失吧

約束を交わす事もなくて 不安が募るばかり
想到相互所约定的那些事情 就会感到越来越不安
ありふれた言葉でもいい 今はただ信じさせて
就算是平常无奇的言语也好 这是如今唯一让我相信的

この慣れた道も 二人なら幸せ
这条熟悉的道路上 是我们两人的话 那我会感到幸福的
届かぬ想いを伝えられたら 未来変わるのかな?
那些无法传达的思念 若是能够传达给你 未来会不会就此发生改变