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 lir.
2. ? l r: find the number of i such that aibi and lir.
 

 

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 nmA and B (1n105,1m3000000,1A,B216) -- the length of the sequence, the number of operations and two parameters.

The second line contains n integers a1,a2,...,an (1ai109). The third line contains n integers b1,b2,...,bn (1bi109)

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 lr 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=1mizi) 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 }
View Code

 

 

 

 

posted @ 2016-09-01 18:36  yanzx6  阅读(102)  评论(0编辑  收藏