4889: [Tjoi2017]不勤劳的图书管理员 树套树
国际惯例的题面(Bzoj没有,洛谷找的):
动态加权逆序对,一眼树套树。
256MB内存,5e4范围,不虚不虚。
首先把交换改成两个插入和两个删除。
考虑插入和删除的贡献,就是统计前面比这个值大的数的数值和,数量和,后面比这个值小的数的数值和,数量和。然后特判一下当前两个值构成逆序对的情况即可(因为这种情况会被计算两遍)。
考虑树状数组套动态开点线段树维护这个东西,线段树只需要单点修改区间求和即可,十分简单。
然而数组开不下啊......理论上我们数组范围要开到2e7左右,然而并跑不满,开到1.4e7就足以AC啦。
(但是跑得奇慢无比,怕不是人傻自带大常数)
代码(话说两个log差不多是根号,我这是两个log还有4倍的常数,大概已经比根号慢了):
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long int lli; 5 const int maxn=5e4+1e2,maxe=1.4e7+1e2; 6 const int mod=1e9+7; 7 8 int in[maxn],seq[maxn],n; 9 10 struct SegmentTree { 11 int lson[maxe],rson[maxe],sum[maxe],siz[maxe],cnt; 12 inline void insert(int &pos,int l,int r,const int &tar,const int &x,const int &d) { 13 if( !pos ) pos = ++cnt; 14 sum[pos] = ( sum[pos] + x ) % mod , siz[pos] += d; 15 if( l == r ) return; 16 const int mid = ( l + r ) >> 1; 17 if( tar <= mid ) insert(lson[pos],l,mid,tar,x,d); 18 else insert(rson[pos],mid+1,r,tar,x,d); 19 } 20 inline int querysum(int pos,int l,int r,const int &ll,const int &rr) { 21 if( !pos || ( ll <= l && r <= rr ) ) return sum[pos]; 22 const int mid = ( l + r ) >> 1; 23 if( rr <= mid ) return querysum(lson[pos],l,mid,ll,rr); 24 else if( ll > mid ) return querysum(rson[pos],mid+1,r,ll,rr); 25 return ( querysum(lson[pos],l,mid,ll,rr) + querysum(rson[pos],mid+1,r,ll,rr) ) % mod; 26 } 27 inline int querysiz(int pos,int l,int r,const int &ll,const int &rr) { 28 if( !pos || ( ll <= l && r <= rr ) ) return siz[pos]; 29 const int mid = ( l + r ) >> 1; 30 if( rr <= mid ) return querysiz(lson[pos],l,mid,ll,rr); 31 else if( ll > mid ) return querysiz(rson[pos],mid+1,r,ll,rr); 32 return ( querysiz(lson[pos],l,mid,ll,rr) + querysiz(rson[pos],mid+1,r,ll,rr) ) % mod; 33 } 34 }sgt; 35 36 struct BinaryIndexTree { 37 int root[maxn],id; 38 #define lowbit(x) (x&-x) 39 inline void update(int x,const int &y,const int &val,const int &vs) { 40 while( x <= n ) sgt.insert(root[x],1,n,y,val,vs) , x += lowbit(x); 41 } 42 inline int querysum(int x,const int &ll,const int &rr) { 43 int ret = 0; 44 while(x) ret = ( ret + sgt.querysum(root[x],1,n,ll,rr) ) % mod , x -= lowbit(x); 45 return ret; 46 } 47 inline int querysiz(int x,const int &ll,const int &rr) { 48 int ret = 0; 49 while(x) ret = ( ret + sgt.querysiz(root[x],1,n,ll,rr) ) % mod , x -= lowbit(x); 50 return ret; 51 } 52 }bit; 53 54 inline int segsum(const int &l,const int &r,const int &ll,const int &rr) { 55 return ( bit.querysum(r,ll,rr) - bit.querysum(l-1,ll,rr) + mod ) % mod; 56 } 57 inline int segsiz(const int &l,const int &r,const int &ll,const int &rr) { 58 return ( bit.querysiz(r,ll,rr) - bit.querysiz(l-1,ll,rr) + mod ) % mod; 59 } 60 61 62 int main() { 63 static int m; 64 static lli now; 65 scanf("%d%d",&n,&m); 66 for(int i=1;i<=n;i++) scanf("%d",seq+i) , scanf("%d",in+seq[i]); 67 for(int i=1;i<=n;i++) { 68 now = ( now + bit.querysum(i,seq[i]+1,n) ) % mod , now = ( now + (lli) bit.querysiz(i,seq[i]+1,n) * in[seq[i]] % mod ) % mod; 69 bit.update(i,seq[i],in[seq[i]],1); 70 } 71 for(int i=1,a,b;i<=m;i++) { 72 scanf("%d%d",&a,&b); 73 if( a > b ) std::swap(a,b); 74 if( a == b ) { 75 printf("%lld\n",now); 76 continue; 77 } 78 now -= segsum(1,a-1,seq[a]+1,n) + segsum(a+1,n,1,seq[a]-1) , now -= (lli) in[seq[a]] * ( segsiz(1,a-1,seq[a]+1,n) + segsiz(a+1,n,1,seq[a]-1) ) % mod , now = ( now % mod + mod ) % mod; 79 now -= segsum(1,b-1,seq[b]+1,n) + segsum(b+1,n,1,seq[b]-1) , now -= (lli) in[seq[b]] * ( segsiz(1,b-1,seq[b]+1,n) + segsiz(b+1,n,1,seq[b]-1) ) % mod , now = ( now % mod + mod ) % mod; 80 bit.update(b,seq[b],mod-in[seq[b]],-1) , bit.update(a,seq[a],mod-in[seq[a]],-1); 81 if( seq[a] > seq[b] ) now = ( now + in[seq[a]] + in[seq[b]] ) % mod; // it have been subed two times . 82 std::swap(seq[a],seq[b]); 83 bit.update(a,seq[a],in[seq[a]],1) , bit.update(b,seq[b],in[seq[b]],1); 84 now += segsum(1,a-1,seq[a]+1,n) + segsum(a+1,n,1,seq[a]-1) , now += (lli) in[seq[a]] * ( segsiz(1,a-1,seq[a]+1,n) + segsiz(a+1,n,1,seq[a]-1) ) % mod , now = ( now % mod + mod ) % mod; 85 now += segsum(1,b-1,seq[b]+1,n) + segsum(b+1,n,1,seq[b]-1) , now += (lli) in[seq[b]] * ( segsiz(1,b-1,seq[b]+1,n) + segsiz(b+1,n,1,seq[b]-1) ) % mod , now = ( now % mod + mod ) % mod; 86 if( seq[a] > seq[b] ) now = ( now - in[seq[a]] - in[seq[b]] + mod ) % mod; // it have been added two times . 87 printf("%lld\n",now); 88 } 89 return 0; 90 }
(另外我为什么又在刷水题了!)
空に舞う雪はまるで白い花びら ひらひら 風に吹かれて散よ
在茫茫天空飞舞着 好似纯白花朵的雪花 迎风飘洒
Ah…染めあげて 消えて無くなるのなら この寂しさも一緒に溶けてゆけ
啊…全都染上純白 如果那些色彩渐渐消失不见的话 那也让这寂寞溶于一起消失吧
約束を交わす事もなくて 不安が募るばかり
想到相互所约定的那些事情 就会感到越来越不安
ありふれた言葉でもいい 今はただ信じさせて
就算是平常无奇的言语也好 这是如今唯一让我相信的
この慣れた道も 二人なら幸せ
这条熟悉的道路上 是我们两人的话 那我会感到幸福的
届かぬ想いを伝えられたら 未来変わるのかな?
那些无法传达的思念 若是能够传达给你 未来会不会就此发生改变