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…染めあげて 消えて無くなるのなら この寂しさも一緒に溶けてゆけ
啊…全都染上純白 如果那些色彩渐渐消失不见的话 那也让这寂寞溶于一起消失吧

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

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

原文地址:https://www.cnblogs.com/Cmd2001/p/8947552.html

时间: 2024-10-05 06:49:50

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

【bzoj4889】: [Tjoi2017]不勤劳的图书管理员 分块-BIT

[bzoj4889]: [Tjoi2017]不勤劳的图书管理员 题目大意:给定一个序列(n<=50000),每个数有一个编码ai(ai<=50000)和权值vi(vi<=100000),每次交换两个数的位置,交换m次(m<=50000) 求每次交换后的序列的杂乱度对1e9+7取模(对于每一对是逆序对的编码会产生两者权值和的杂乱度). 感觉正解是什么奇怪的树套树?蒟蒻只会分块水题.. 先用BIT求一遍初始状态的杂乱度..(不要问我为什么一开始是BIT..因为打暴力正好用到就懒得改了.

洛谷P3759 - [TJOI2017]不勤劳的图书管理员

Portal Description 给出一个\(1..n(n\leq5\times10^4)\)的排列\(\{a_n\}\)和数列\(\{w_n\}(w_i\leq10^5)\),进行\(m(m\leq5\times10^4)\)次操作: 交换\(a_{p_1},a_{p_2}\),并求\(\sum_{i=1}^n \sum_{j=i+1}^n [a_i>a_j](w_{a_i}+w_{a_j})\). Solution 树套树/CDQ分治,想锻炼一下代码能力所以写了树套树. 首先这是一个求逆

P3759 [TJOI2017]不勤劳的图书管理员 [树套树]

树套树是什么啊我不知道/dk 我只知道卡常数w // by Isaunoya #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize( "inline,-fgcse,-fgcse-lm,-fipa-sra,-ftree-pre,-ftree-vrp,-fpeephole2,-ffast-math,-fsched-spec,unroll-

题解【[TJOI2017]不勤劳的图书管理员】

\[ \texttt{Description} \] 给两个长度为 \(n\) 的数列 \(A\) 和 \(B\) . 记 \(A\) 的逆序对(满足 \(x<y\),\(A_x>A_y\) 的数对 \((x,y)\) )对答案的贡献为 \(B_x+B_y\) . 通俗地说,答案就是 \(\sum\limits_{x < y \ \& \ A_x > A_y}\) \(B_x+B_y\). 一共 \(m\) 次交换,每次交换 \(A_x\) 和 \(A_y\) ,\(B_x

[P3759][TJOI2017]不勤劳的图书管理员(分块+树状数组)

题目描述 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生 这两本书页数的和的厌烦度.现在有n本被打乱顺序的书,在接下来m天中每天都会因为读者的阅览导致书籍顺序改变位置.因为小豆被要求在接下来的m天中至少 要整理一次图书.小豆想知道,如果他前i天不去整理,第i天他的厌烦度是多少,这样他好选择厌烦度最小的那天去整理. 输入输出格式 输入格式: 第一行会有两个数,n,m分别表示有n本书,m天 接下来n行,每行两

[bzoj4889] [Tjoi2017]不勤劳的图书管理员

Description 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度.现在有n本被打乱顺序的书,在接下来m天中每天都会因为读者的阅览导致书籍顺序改变位置.因为小豆被要求在接下来的m天中至少要整理一次图书.小豆想知道,如果他前i天不去整理,第i天他的厌烦度是多少,这样他好选择厌烦度最小的那天去整理. Input 第一行会有两个数,n,m分别表示有n本书,m天 接下来n行,每行两个数

BZOJ_3196_二逼平衡树(树套树:线段树+Treap)

描述 可以处理区间问题的平衡树. 分析 树套树.可以用线段树套Treap.人生第一道树套树的题... op1:如果在整区间,直接在该区间的treap上求解.否则分两个区间求解,然后相加.最后+1. op2:这个不太好直接做,可以二分,每次假定一个值,用这个值去做op1,以此求得一个rank=k+1的数,求rank=k的数等价与求这个数的前驱pre. op3:先删后加. op4&op5:如果在整区间,直接在该区间的treap上求解,否则分量个区间求解,pre取最大值,suc取最小值.注意有些数在有

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

[BZOJ3110] [Zjoi2013] K大数查询 (树套树)

Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Output 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 Sample Output 1 2 1 HINT [