Differencia (归并树)
归并树,与我们原学过的归并排序是一样的原理,但是在那个的基础上进行扩展应用。首先每个节点储存了它每个节点所代表的点的有序序列,还有就是每个点里面包含的所有的b[i]在左右子树的排名辅助更新数据,还有一个用来记录当前节点a[] >b[] 的数量的num。这时候查询的话就是线段树查询了,然后更新,首先求出要更新进去的点在原本数组的排名,然后就可以将该数据更新进去范围里面的lazy数组了,那么这时候lazy数组怎么使用?其实你这个lazy数组就是你更新进来的数据在确定范围内的一个排名,那么你这个排名就是a[] > b[] 的数量了。当然不可能更新所有的节点,所以需要使用lazydown的方法优化时间。
#include<bits/stdc++.h> #define debug 0 #define Lson (rt << 1) #define Rson ((rt << 1) | 1) #define M ((l + r) / 2) using namespace std; const long long mod = 1e9 + 7; const int maxn = 111111; int T, n, m, ans, last, cnt, L, R, X; int a[maxn], b[maxn], st[maxn * 4], en[maxn * 4], lazy[maxn * 4], num[maxn * 4]; int pl[maxn * 17], pr[maxn * 17], pool[maxn * 17]; void Build(int l, int r, int rt){ lazy[rt] = -1; if(l == r){ st[rt] = ++cnt;en[rt] = cnt; pool[cnt] = b[l]; num[rt] = (a[l] >= b[l]); return ; } Build(l, M, Lson);Build(M + 1, r, Rson); num[rt] = num[Lson] + num[Rson]; int leftL = st[Lson], leftR = en[Lson]; int rightL = st[Rson], rightR = en[Rson]; st[rt] = cnt + 1; while(leftL <= leftR && rightL <= rightR)pool[++cnt] = ((pool[leftL] <= pool[rightL]) ? pool[leftL ++] : pool[rightL ++]); while(leftL <= leftR)pool[++cnt] = pool[leftL ++]; while(rightL <= rightR)pool[++cnt] = pool[rightL ++]; en[rt] = cnt; leftL = st[Lson], rightL = st[Rson]; for(int i = st[rt]; i <= en[rt]; i ++){ while(leftL <= leftR && pool[leftL] <= pool[i]) leftL ++; while(rightL <= rightR && pool[rightL] <= pool[i]) rightL ++; pl[i] = leftL - 1; pr[i] = rightL - 1; if(pl[i] < st[Lson]) pl[i] = 0; if(pr[i] < st[Rson]) pr[i] = 0; } } void Lazy(int rt, int pos){ num[rt] = pos ? pos - st[rt] + 1 : 0; lazy[rt] = pos; } void Pushdown(int rt){ if(lazy[rt] == -1) return ; int pos = lazy[rt]; Lazy(Lson, pl[pos]); Lazy(Rson, pr[pos]); lazy[rt] = -1; } int erfen(int x){ int l = st[1], r = en[1], ans = 0; while(l <= r){ if(pool[M] <= x){ ans = M; l = M + 1;} else r = M - 1; } return ans; } void query(int l, int r, int rt){ if(L <= l && r <= R){ last += num[rt]; return ; } Pushdown(rt); if(L <= M) query(l, M, Lson); if(R > M) query(M + 1, r, Rson); num[rt] = num[Lson] + num[Rson]; } void Update(int l, int r, int pos, int rt){ if(L <= l && r <= R){ Lazy(rt, pos);return ; } Pushdown(rt); if(L <= M) Update(l, M, pl[pos], Lson); if(R > M) Update(M + z1, r, pr[pos], Rson); num[rt] = num[Lson] + num[Rson]; } int AA,BB,CC = ~(1<<31),MM = (1<<16) - 1; int rnd(){ AA = (36969 + (last >> 3)) * (AA&MM) + (AA >> 16); BB = (18000 + (last >> 3)) * (BB&MM) + (BB >> 16); return (CC & ((AA << 16) + BB)) % 1000000000; } int main(){ int n,m; scanf("%d", &T);while(T --){ ans = last = cnt = 0; scanf("%d%d%d%d", &n, &m, &AA, &BB); for(int i = 1; i <= n; i ++) scanf("%d",&a[i]); for(int i = 1; i <= n; i ++) scanf("%d",&b[i]); Build(1, n, 1); for(int i = 1; i <= m; i ++){ L = rnd()%n + 1; R = rnd()%n + 1; X = rnd() + 1; if(L > R)swap(L, R); if((L + R + X) & 1) Update(1, n, erfen(X), 1); else{ last = 0; query(1, n, 1); ans = (1LL * i * last % mod + ans) % mod; } } printf("%d\n",ans); } return 0; }
more crazy more get!