2016 Multi-University Training Contest 2 D. Differencia
Differencia
Time Limit: 10000/10000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 601 Accepted Submission(s): 173
Problem Description
Professor Zhang has two sequences a1,a2,...,an and b1,b2,...,bn. He wants to perform two kinds of operations on the sequences:
1. + l r x: set ai to x for all l≤i≤r.
2. ? l r: find the number of i such that ai≥bi and l≤i≤r.
1. + l r x: set ai to x for all l≤i≤r.
2. ? l r: find the number of i such that ai≥bi and l≤i≤r.
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains four integers n, m, A and B (1≤n≤105,1≤m≤3000000,1≤A,B≤216) -- the length of the sequence, the number of operations and two parameters.
The second line contains n integers a1,a2,...,an (1≤ai≤109). The third line contains n integers b1,b2,...,bn (1≤bi≤109).
As there are too many operations, the m operations are specified by parameters A and B given to the following generator routine.
For the i-th operation, first call rnd(last) three times to get l, r and x (i.e. l = rnd(last) % n + 1, r = rnd(last) % n + 1, x = rnd(last) + 1). Then if l>r, you should swap their value. And at last, the i-th operation is type ?, if (l+r+x) is an even number, or type + otherwise.
Note: last is the answer of the latest type ? operation and assume last=0 at the beginning of each test case.
The first line contains four integers n, m, A and B (1≤n≤105,1≤m≤3000000,1≤A,B≤216) -- the length of the sequence, the number of operations and two parameters.
The second line contains n integers a1,a2,...,an (1≤ai≤109). The third line contains n integers b1,b2,...,bn (1≤bi≤109).
As there are too many operations, the m operations are specified by parameters A and B given to the following generator routine.
int a = A, b = B, C = ~(1<<31), M = (1<<16)-1;
int rnd(int last) {
a = (36969 + (last >> 3)) * (a & M) + (a >> 16);
b = (18000 + (last >> 3)) * (b & M) + (b >> 16);
return (C & ((a << 16) + b)) % 1000000000;
}
For the i-th operation, first call rnd(last) three times to get l, r and x (i.e. l = rnd(last) % n + 1, r = rnd(last) % n + 1, x = rnd(last) + 1). Then if l>r, you should swap their value. And at last, the i-th operation is type ?, if (l+r+x) is an even number, or type + otherwise.
Note: last is the answer of the latest type ? operation and assume last=0 at the beginning of each test case.
Output
For each test case, output an integer S=(∑i=1mi⋅zi) mod (109+7), where zi is the answer for i-the query. If the i-th query is of type +, then zi=0.
Sample Input
3
5 10 1 2
5 4 3 2 1
1 2 3 4 5
5 10 3 4
5 4 4 2 1
1 2 3 4 5
5 10 5 6
5 4 5 2 1
1 2 2 4 5
Sample Output
81
88
87
Author
zimpha
Source
题意: 维护数组a,两种操作: 1、l~r全部赋值为x 2、l~r查询满足a[i]>=b[i]的i有多少个。
题解: 其实官方题解已经很清楚了: 这道题O(nlog2n)的线段树套有序表做法很显然. 线段树每个节点[l,r]维护这个区间内, 数组bb排序好的结果. 然后对于修改操作, 只要在这个区间内二分一下就能知道这个区间的答案 (往子节点标记时也同理). 这个做法常数很小, 跑的很快, 但是应该被卡了 (没测过zkw写法, 也许能过), 理由参考第一句话. 上面方法稍作修改就可以得到一个O(nlogn)的做法, 除了有序表线段树每个节点同时维护有序表第ii个数进入左右子树时的位置. 那么只要在线段树根节点做一次二分, 之后就可以O(1)查询这个数在左右子树的rank变化. 这个对线段树往下push lazy标记也是适用的. 本质就是归并树。 假设现在对于修改操作,对于某个节点的有序表,我知道前k个满足b[i]<=x 那么只要预处理出到i位置,这前i个,有lsh个进入左子树,rsh进入右子树。 那么对于左子树,它的有序表前lsh全是满足b[i]<=x的。 同理,右子树的有序表前rsh个也是满足b[i]<=x的。 这样我们只用二分一次,接下来就能推出子树所有的情况了。 当遇到目标区间是,就知道这个区间有k‘个满足b[i]<=x了 这个k'是父亲直接传下来的(是lsh或者rsh)。 然后直接打懒惰标记好了。 询问就是求和操作。
1 const int N = 100010, M = 20, MOD = 1e9 + 7; 2 struct MergeTree { 3 static struct Node { 4 static int tot; 5 int child[2], cnt; 6 bool tag; 7 int lside; 8 9 inline void init() { 10 child[0] = child[1] = -1, cnt = lside = 0, tag = false; 11 } 12 } tr[N * M]; 13 static int tol[N * M], len; 14 15 #define child(x, y) tr[x].child[y] 16 #define lc(x) child(x, 0) 17 #define rc(x) child(x, 1) 18 #define cnt(x) tr[x].cnt 19 #define tag(x) tr[x].tag 20 #define lside(x) tr[x].lside 21 #define tol(x, y) (y ? tol[lside(x) + y - 1] : 0) 22 #define tor(x, y) (y ? y - tol[lside(x) + y - 1] : 0) 23 24 inline static void init() { 25 Node::tot = 0, len = 0; 26 } 27 28 inline static void pushdown(int x) { 29 if(tag(x)) { 30 tag(lc(x)) = tag(rc(x)) = true, tag(x) = false; 31 cnt(lc(x)) = tol(x, cnt(x)), cnt(rc(x)) = tor(x, cnt(x)); 32 } 33 } 34 35 inline static void updata(int x) { 36 cnt(x) = 0; 37 for(int i = 0; i < 2; ++i) cnt(x) += cnt(child(x, i)); 38 } 39 40 inline static void build(int &x, int l, int r, int a[], int b[]) { 41 static int tmp[N]; 42 if(x < 0) tr[x = Node::tot++].init(); 43 if(l >= r) cnt(x) = (a[l] >= b[l]); 44 else { 45 int mid = (l + r) >> 1; 46 build(lc(x), l, mid, a, b), build(rc(x), mid + 1, r, a, b); 47 updata(x); 48 49 int indexL = l, indexR = mid + 1, now = l; 50 lside(x) = len; 51 while(indexL <= mid && indexR <= r) { 52 if(len > lside(x)) tol[len] = tol[len - 1]; 53 else tol[len] = 0; 54 if(b[indexL] <= b[indexR]) 55 ++tol[len], tmp[now++] = b[indexL++]; 56 else tmp[now++] = b[indexR++]; 57 ++len; 58 } 59 while(indexL <= mid) { 60 tol[len] = tol[len - 1] + 1; 61 tmp[now++] = b[indexL++], ++len; 62 } 63 while(indexR <= r) { 64 tol[len] = tol[len - 1]; 65 tmp[now++] = b[indexR++], ++len; 66 } 67 for(int i = l; i <= r; ++i) b[i] = tmp[i]; 68 } 69 } 70 71 inline static int query(int x, int l, int r, int lef, int rig) { 72 if(rig < l || lef > r) return 0; 73 if(lef <= l && r <= rig) return cnt(x); 74 int mid = (l + r) >> 1; 75 pushdown(x); 76 return query(lc(x), l, mid, lef, rig) + 77 query(rc(x), mid + 1, r, lef, rig); 78 } 79 80 inline static void modify(int x, int l, int r, 81 int rk, int lef, int rig) { 82 if(rig < l || lef > r) return; 83 if(lef <= l && r <= rig) cnt(x) = rk, tag(x) = true; 84 else { 85 pushdown(x); 86 int mid = (l + r) >> 1; 87 modify(lc(x), l, mid, tol(x, rk), lef, rig); 88 modify(rc(x), mid + 1, r, tor(x, rk), lef, rig); 89 updata(x); 90 } 91 } 92 93 #undef child 94 #undef lc 95 #undef rc 96 #undef cnt 97 #undef tag 98 #undef lside 99 #undef tol 100 #undef tor 101 }; 102 int MergeTree::Node::tot, MergeTree::tol[N * M], MergeTree::len; 103 MergeTree::Node MergeTree::tr[N * M]; 104 int n, m, A, B; 105 int a[N], b[N]; 106 107 int C = ~(1 << 31), MM = (1 << 16) - 1; 108 inline int rnd(int last) { 109 A = (36969 + (last >> 3)) * (A & MM) + (A >> 16); 110 B = (18000 + (last >> 3)) * (B & MM) + (B >> 16); 111 return (C & ((A << 16) + B)) % 1000000000; 112 } 113 114 inline void solve() { 115 MergeTree::init(); 116 int root = -1, lst = 0, ans = 0; 117 MergeTree::build(root, 0, n - 1, a, b); 118 for(int index = 1; index <= m; ++index) { 119 int l = rnd(lst) % n + 1, r = rnd(lst) % n + 1, x = rnd(lst) + 1; 120 if(l > r) swap(l, r); 121 --l, --r; 122 if((l + r + x) & 1) { 123 int rk = upper_bound(b, b + n, x) - b; 124 MergeTree::modify(root, 0, n - 1, rk, l, r); 125 } else { 126 lst = MergeTree::query(root, 0, n - 1, l, r); 127 ans = (ans + index * 1ll * lst) % MOD; 128 } 129 } 130 131 printf("%d\n", ans); 132 } 133 134 int main() { 135 int testCase; 136 scanf("%d", &testCase); 137 while(testCase--) { 138 scanf("%d%d%d%d", &n, &m, &A, &B); 139 for(int i = 0; i < n; ++i) scanf("%d", &a[i]); 140 for(int i = 0; i < n; ++i) scanf("%d", &b[i]); 141 solve(); 142 } 143 return 0; 144 }