Luogu 3759 [TJOI2017]不勤劳的图书管理员
再也不作死写FhqTreap作内层树了,卡的不如暴力呜呜呜……
题意翻译:给一个序列,每个下标包含两个属性$a$和$v$,求第一个属性与下标形成的所有逆序对的第二个属性和,给出$m$个交换两个下标的操作,每次操作之后查询。
考虑一下交换之后会发生什么:
假设这次要交换$x$和$y$,使$x \leq y$。
发现交换之后$x, y$和$x$的左边的数和$y$右边的数构成的逆序对产生的贡献不变,发生变化的是中间的数。
那么问题就简单了,只要先消去中间的数和$x, y$的贡献,具体来说就是$[x + 1, y - 1]$这个区间中$a_{i}$比$a_{x}$小的$b_{i}$和,以及$a_{i}$比$a_{y}$大的$b_{i}$和。
发现$(x, y)$可能也会构成一个逆序对,拎出来判一下可以保证这一对只被计算一次。
然后算一下交换之后产生的贡献,方法类似。
树套树维护即可。
时间复杂度$O(nlog^{2}n)$。
Code:
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = 5e4 + ;
const int M = 2e7 + ;
const ll P = 1e9 + ; int n, m, a[N];
ll v[N], ans = 0LL; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} template <typename T>
inline void swap(T &x, T &y) {
T t = x; x = y; y = t;
} namespace BinaryIndexTree {
int cnt[N]; ll s[N]; #define lowbit(x) (x & (-x)) inline void modifyS(int p, ll val) {
for(; p <= n; p += lowbit(p)) s[p] = (s[p] + val) % P;
} inline void modifyC(int p) {
for(; p <= n; p += lowbit(p)) cnt[p]++;
} inline ll getSum(int p) {
ll res = ;
for(; p > ; p -= lowbit(p)) res = (res + s[p]) % P;
return res;
} inline int getCnt(int p) {
int res = ;
for(; p > ; p -= lowbit(p)) res += cnt[p];
return res;
} #undef lowbit } using namespace BinaryIndexTree; namespace Tree {
int nodeCnt, root[N * ];
struct Node {
int lc, rc, siz;
ll sum;
} s[M]; #define mid ((l + r) >> 1) inline void up(int p) {
if(!p) return;
s[p].siz = s[s[p].lc].siz + s[s[p].rc].siz;
s[p].sum = (s[s[p].lc].sum + s[s[p].rc].sum) % P;
} void modify(int &p, int l, int r, int x, ll selV) {
if(!p) p = ++nodeCnt;
if(l == r) {
s[p].siz = (selV != -);
s[p].sum = (selV == - ? : selV % P);
return;
} if(x <= mid) modify(s[p].lc, l, mid, x, selV);
else modify(s[p].rc, mid + , r, x, selV);
up(p);
} ll query(int p, int l, int r, int x, int y, ll selV) {
if(!p) return 0LL;
if(x <= l && y >= r) return (selV * s[p].siz % P + s[p].sum) % P; ll res = 0LL;
if(x <= mid) res = (res + query(s[p].lc, l, mid, x, y, selV)) % P;
if(y > mid) res = (res + query(s[p].rc, mid + , r, x, y, selV)) % P;
return res;
} #define lowbit(p) (p & (-p)) inline void change(int p, int val, ll selV) {
for(; p <= n; p += lowbit(p))
modify(root[p], , n, val, selV);
} inline void clear(int p, int val) {
for(; p <= n; p += lowbit(p))
modify(root[p], , n, val, -);
} inline ll ask(int p, int v, ll selV, int type) {
ll res = 0LL;
for(; p > ; p -= lowbit(p)) {
if(type) res = (res + query(root[p], , n, v + , n, selV)) % P;
else res = (res + query(root[p], , n, , v - , selV)) % P;
}
return res;
} inline ll qSum(int l, int r, int v, ll selV, int type) {
return (ask(r, v, selV, type) - ask(l - , v, selV, type) + P) % P;
} } using namespace Tree; int main() {
read(n), read(m);
nodeCnt = ;
for(int i = ; i <= n; i++) {
read(a[i]), read(v[i]);
ans = (ans + (getSum(n) - getSum(a[i]) + P) % P + P + v[i] * (getCnt(n) - getCnt(a[i])) % P + P) % P;
modifyS(a[i], v[i]), modifyC(a[i]);
change(i, a[i], v[i]);
} for(int x, y; m--; ) {
read(x), read(y);
if(x == y) {
printf("%lld\n", ans);
continue;
}
if(x > y) swap(x, y); ll res = 0LL;
if(x + <= y - ) {
res = (res + qSum(x + , y - , a[y], v[y], )) % P;
res = (res + qSum(x + , y - , a[x], v[x], )) % P;
}
if(a[y] < a[x]) res = ((res + v[x]) % P + v[y]) % P; ans = (ans - res + P) % P; res = 0LL;
if(x + <= y - ) {
res = (res + qSum(x + , y - , a[y], v[y], )) % P;
res = (res + qSum(x + , y - , a[x], v[x], )) % P;
} if(a[y] > a[x]) res = ((res + v[x]) % P + v[y]) % P;
ans = (ans + res) % P; printf("%lld\n", ans); clear(x, a[x]), clear(y, a[y]);
change(x, a[y], v[y]), change(y, a[x], v[x]);
swap(a[x], a[y]), swap(v[x], v[y]);
} return ;
}
树状数组套线段树(100 pts)
// luogu-judger-enable-o2
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
typedef long long ll; const int N = 5e4 + ;
const int M = 2e7 + ;
const ll P = 1e9 + ; int n, m, a[N];
ll v[N], ans = ; namespace FhqTreap {
int root[M], nodeCnt, ch[M][], pri[M], siz[M];
ll key[M], sum[M], sel[M]; #define lc ch[p][0]
#define rc ch[p][1] inline void up(int p) {
if(p) {
siz[p] = siz[lc] + siz[rc] + ;
sum[p] = (sum[lc] % P + sum[rc] % P + sel[p] % P) % P;
}
} inline int newnode(ll val, ll selV) {
++nodeCnt;
key[nodeCnt] = val, sum[nodeCnt] = sel[nodeCnt] = selV;
pri[nodeCnt] = rand(), siz[nodeCnt] = ;
return nodeCnt;
} void split(int p, ll val, int &x, int &y) {
if(!p) x = y = ;
else {
if(val >= key[p])
x = p, split(rc, val, rc, y);
else
y = p, split(lc, val, x, lc);
up(p);
}
} int merge(int x, int y) {
if(!x || !y) return x + y;
else {
if(pri[x] < pri[y]) {
ch[x][] = merge(ch[x][], y);
up(x);
return x;
} else {
ch[y][] = merge(x, ch[y][]);
up(y);
return y;
}
}
} inline void insert(int rt, ll val, ll selV) {
if(!root[rt]) {
root[rt] = newnode(val, selV);
return;
}
int x, y;
split(root[rt], val, x, y);
root[rt] = merge(x, merge(newnode(val, selV), y));
} inline void remove(int rt, ll val) {
int x, y, z;
split(root[rt], val, x, y);
split(x, val - , x, z);
z = merge(ch[z][], ch[z][]);
root[rt] = merge(merge(x, z), y);
} inline ll ask(int rt, ll val, ll selV, int type) {
int x, y; ll res;
if(type) {
split(root[rt], val, x, y);
res = (selV * siz[x] % P + sum[x]) % P;
} else {
split(root[rt], val, x, y);
res = (selV * siz[y] % P + sum[y]) % P;
}
root[rt] = merge(x, y);
return res % P;
} void Pi(int p, int *arr) {
if(lc) Pi(lc, arr);
printf("%d ", arr[p]);
if(rc) Pi(rc, arr);
} #undef lc
#undef rc
}; namespace SegT {
using namespace FhqTreap; #define lc p << 1
#define rc p << 1 | 1
#define mid ((l + r) >> 1) void ins(int p, int l, int r, int x, ll val, ll selV) {
insert(p, val, selV);
if(l == r) return;
if(x <= mid) ins(lc, l, mid, x, val, selV);
else ins(rc, mid + , r, x, val, selV);
} void del(int p, int l, int r, int x, ll val) {
remove(p, val);
if(l == r) return;
if(x <= mid) del(lc, l, mid, x, val);
else del(rc, mid + , r, x, val);
} ll query(int p, int l, int r, int x, int y, ll val, ll selV, int type) {
if(x <= l && y >= r) return ask(p, val, selV, type) % P; ll res = ;
if(x <= mid) res = (res + query(lc, l, mid, x, y, val, selV, type)) % P;
if(y > mid) res = (res + query(rc, mid + , r, x, y, val, selV, type)) % P;
return res;
} void print(int p, int l, int r, int *arr) {
Pi(root[p], arr), printf("\n");
if(l == r) return;
print(lc, l, mid, arr), print(rc, mid + , r, arr);
} } using namespace SegT; template <typename T>
inline void swap(T &x, T &y) {
T t = x;
x = y;
y = t;
} namespace IOstream{
const int L = << ; char buffer[L], *S, *T; inline char Getchar() {
if(S == T) {
T = (S = buffer) + fread(buffer, , L, stdin);
if(S == T) return EOF;
}
return *S++;
} template <class T>
inline void read(T &X) {
char ch; T op = ;
for(ch = Getchar(); ch > '' || ch < ''; ch = Getchar())
if(ch == '-') op = -;
for(X = ; ch >= '' && ch <= ''; ch = Getchar())
X = (X << ) + (X << ) + ch - '';
X *= op;
} template <typename T>
inline void write(T x)
{
T sta[]; int len = ;
if(x < ) putchar('-'), x = -x;
if(x == ) {
putchar('');
return;
}
for(; x > ; sta[++len] = x % , x /= );
for(int i = len; i >= ; i--) putchar(sta[i] + '');
} } using namespace IOstream; namespace BinaryIndexTree {
int cnt[N]; ll s[N]; #define lowbit(x) (x & (-x)) inline void modifyS(int p, ll val) {
for(; p <= n; p += lowbit(p)) s[p] = (s[p] + val) % P;
} inline void modifyC(int p) {
for(; p <= n; p += lowbit(p)) cnt[p]++;
} inline ll getSum(int p) {
ll res = ;
for(; p > ; p -= lowbit(p)) res = (res + s[p]) % P;
return res;
} inline int getCnt(int p) {
int res = ;
for(; p > ; p -= lowbit(p)) res += cnt[p];
return res;
} } using namespace BinaryIndexTree; int main() {
// freopen("1.in", "r", stdin);
// freopen("mine.out", "w", stdout); // srand(19260817); read(n), read(m);
nodeCnt = ;
for(int i = ; i <= n; i++) {
read(a[i]), read(v[i]);
ans = (ans + (getSum(n) - getSum(a[i]) + P) % P + P + v[i] * (getCnt(n) - getCnt(a[i])) % P + P) % P;
modifyS(a[i], v[i]), modifyC(a[i]);
ins(, , n, i, a[i], v[i]);
} // printf("%d\n", ans); for(int x, y; m--; ) {
read(x), read(y);
if(x == y) {
printf("%lld\n", ans);
continue;
}
if(x > y) swap(x, y); ll res = ;
if(x + <= y - ) {
res = (res + query(, , n, x + , y - , a[y], v[y], )) % P;
res = (res + query(, , n, x + , y - , a[x], v[x], )) % P;
}
if(a[y] < a[x]) res = (res % P + v[x] % P + v[y] % P) % P;
ans = (ans - res + P) % P; res = ;
if(x + <= y - ) {
res = (res + query(, , n, x + , y - , a[y], v[y], )) % P;
res = (res + query(, , n, x + , y - , a[x], v[x], )) % P;
}
if(a[y] > a[x]) res = (v[y] % P + v[x] % P + res % P) % P;
ans = (ans + res) % P; write(ans), puts(""); del(, , n, x, a[x]), del(, , n, y, a[y]);
ins(, , n, y, a[x], v[x]), ins(, , n, x, a[y], v[y]);
swap(a[x], a[y]), swap(v[x], v[y]); /* print(1, 1, n, key), printf("\n");
print(1, 1, n, sel), printf("\n"); */
} return ;
}
线段树套fhqTreap (20 pts)
Luogu 3759 [TJOI2017]不勤劳的图书管理员的更多相关文章
- LUOGU P3759 [TJOI2017]不勤劳的图书管理员(树套树)
传送门 解题思路 和以前做过的一道题有点像,就是区间逆序对之类的问题,用的是\(BIT\)套权值线段树,交换时讨论一下计算答案..跑的不如暴力快.. 代码 #include<iostream&g ...
- 【bzoj4889】: [Tjoi2017]不勤劳的图书管理员 分块-BIT
[bzoj4889]: [Tjoi2017]不勤劳的图书管理员 题目大意:给定一个序列(n<=50000),每个数有一个编码ai(ai<=50000)和权值vi(vi<=100000 ...
- 【BZOJ4889】[Tjoi2017]不勤劳的图书管理员 分块+树状数组
[BZOJ4889][Tjoi2017]不勤劳的图书管理员 题目描述 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让 ...
- 洛谷P3759 - [TJOI2017]不勤劳的图书管理员
Portal Description 给出一个\(1..n(n\leq5\times10^4)\)的排列\(\{a_n\}\)和数列\(\{w_n\}(w_i\leq10^5)\),进行\(m(m\l ...
- 【loj2639】[Tjoi2017]不勤劳的图书管理员
#2639. 「TJOI2017」不勤劳的图书管理员 题目描述 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产 ...
- BZOJ4889 & 洛谷3759:[TJOI2017]不勤劳的图书管理员——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4889 https://www.luogu.org/problemnew/show/P3759 加里 ...
- 【洛谷3759】[TJOI2017] 不勤劳的图书管理员(树套树)
点此看题面 大致题意: 给定一个序列,每个元素有两个属性\(a_i\)和\(v_i\),每次操作改变两个元素的位置,求每次操作后\(\sum{v_i+v_j}[i<j,a_i>a_j]\) ...
- [P3759][TJOI2017]不勤劳的图书管理员(分块+树状数组)
题目描述 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生 这两本书页数的和的厌烦度.现在有n本被打乱顺序的书 ...
- [bzoj4889] [Tjoi2017]不勤劳的图书管理员
Description 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度.现在有n本被 ...
随机推荐
- 使用visio 2010建立sql server数据模型——手动画、利用逆向工程
基础数据库这个词不在新鲜,老早就提出了.咱们从出生,个人信息就被放到一个基本信息库中了,在全国各地,通过身份证号就能知道你的基本信息.最近米老师 下发了一个任务,让我们开发几个小项目,考试系统.选修课 ...
- python使用 db.select 返回的数据只能遍历一次
python中通过find从mongo中查出的数据,或者通过select返回的数据,其实返回的是游标,当你进行便利一次之后,游标指向最后, 所以当你再一次进行便利时,便出现数据为空的现象. 解决办法: ...
- VueJs路由跳转——vue-router的使用
对于单页应用,官方提供了vue-router进行路由跳转的处理,本篇主要也是基于其官方文档写作而成. 安装 基于传统,我更喜欢采用npm包的形式进行安装. npm install vue-router ...
- Python3.7安装pyspider
下面是Python3.7安装pyspider的方式,能安装成功但是后期有很多问题,所以不建议,请使用3.5版本的Python进行安装!!!由于要做爬虫工作,所以学习pyspider框架,下面介绍安装步 ...
- Laser
Petya is the most responsible worker in the Research Institute. So he was asked to make a very impor ...
- Jtable实现
package database; import java.util.Vector; import javax.swing.table.AbstractTableModel; public class ...
- Linux查看硬件信息(北桥芯片组、南桥、PCI接口、CPU等)
Linux查看硬件信息(北桥芯片组.南桥.PCI接口.CPU等) Linux查看硬件信息(北桥芯片组.南桥.PCI接口.CPU等) 查看MCH(北桥) 查看ICH(南桥) 查看CPU 查看pci接口设 ...
- [转]HTTP详解(1)-工作原理
1. HTTP简介 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议.它可以使浏览器更加高效,使网络传输减少. ...
- loj 2542 随机游走 —— 最值反演+树上期望DP+fmt
题目:https://loj.ac/problem/2542 因为走到所有点的期望就是所有点期望的最大值,所以先最值反演一下,问题变成从根走到一个点集任意一点就停止的期望值: 设 \( f[x] \) ...
- 4、运行成功的Demo(PyCharm+Selenium)
1.打开PyCharm,新建一个python.file,输入代码“from selenium import webdriver”报错的解决方法 (1)PyCharm没有找到正确的python,在“Fi ...