1. 程式人生 > >【UOJ #46】 【清華集訓2014】玄學

【UOJ #46】 【清華集訓2014】玄學

clas 並且 for fine 不讓 改變 成了 表示 真的

題目描述

巨醬有 n 副耳機,他把它們擺成了一列,並且由 1 到n依次編號。每個耳機有一個玄學值,反映了各自的一些不可名狀的獨特性能。玄學值都是 0 到 m-1 間的整數。在外界的作用下(包括但不限於換線、上放、更換電源為核電、讓kAc叔叔給它們講故事),這些耳機的玄學值會發生改變。特別地,巨醬觀察發現,每種作用 o 對應了兩個整數 ao與 bo,在這種作用之後,玄學值原本為 x 的耳機,其玄學值恰會變成 (aox+bo)modm。

巨醬對他手頭耳機的表現並不滿意,遺憾的是,最近他並不有錢,無法任性,不能趕緊買買買以滿足自己。手頭緊張的他準備擬定一個相對經濟的方案,通過各種作用來改善他手頭玩具的性能。具體地說,為了盡快完成方案的制訂,巨醬希望自己能高效地完成以下工作:

巨醬想到了一種操作,能讓耳機的玄學值由 x 變為 (ax+b)modm,並且他計劃對編號為 i 到 j 的耳機執行這種操作。
巨醬想知道如果將(並且僅將)自己的第 i 個到第 j 個計劃按順序付諸行動,編號為 k 的耳機的玄學值將會變成多少。
出於著名算法競賽選手的矜持,巨醬表示自己才不需要你的幫助。但是如果巨醬真的厭倦了自己的玩具,它們就會被50包郵出給主席。為了不讓後者白白撿到便宜,你考慮再三還是決定出手。

題解

二進制分組的思想。

用線段樹維護時間的操作序列,每次操作一個一個往線段樹裏面插,等到一個線段被插滿的時候用歸並來維護區間的信息。查詢的時候如果一個線段沒有被插滿就遞歸下去。定位到一個區間的時候在區間裏面歸並出來的信息二分。

代碼

 1 #include <cstdio>
 2 
 3 #define maxn 100010
 4 #define maxm 600010
 5 #define R register
 6 int x[maxn], tnum;
 7 struct Seg {
 8     int l, r, a, b;
 9 } p[maxn * 200];
10 int lef[maxm << 2], rig[maxm << 2], pcnt, ta, tb, ql, qr, n, m, k, ans;
11 void update(R int o, R int
l, R int r) 12 { 13 lef[o] = pcnt + 1; 14 for (R int i = lef[o << 1], j = lef[o << 1 | 1], head = 1; i <= rig[o << 1] || j <= rig[o << 1 | 1]; ) 15 if (p[i].r <= p[j].r) 16 { 17 p[++pcnt] = (Seg) {head, p[i].r, 1ll * p[i].a * p[j].a % m, (1ll * p[j].a * p[i].b + p[j].b) % m}; 18 head = p[i].r + 1; 19 p[i].r == p[j].r ? ++j : 0; ++i; 20 } 21 else 22 { 23 p[++pcnt] = (Seg) {head, p[j].r, 1ll * p[i].a * p[j].a % m, (1ll * p[j].a * p[i].b + p[j].b) % m}; 24 head = p[j].r + 1; ++j; 25 } 26 rig[o] = pcnt; 27 } 28 int find(R int o, R int t, R int &s) 29 { 30 R int l = lef[o], r = rig[o]; 31 while (l < r) 32 { 33 R int mid = l + r >> 1; 34 if (t <= p[mid].r) r = mid; 35 else l = mid + 1; 36 } 37 // printf("%d %d t %d s %d %d %d\n", p[l].l, p[l].r, t, s, p[l].a, p[l].b); 38 s = (1ll * s * p[l].a + p[l].b) % m; 39 } 40 void modify(R int o, R int l, R int r, R int t) 41 { 42 if (l == r) 43 { 44 lef[o] = pcnt + 1; 45 ql > 1 ? p[++pcnt] = (Seg) {1, ql - 1, 1, 0}, 1: 0; 46 p[++pcnt] = (Seg) {ql, qr, ta, tb}; 47 qr < n ? p[++pcnt] = (Seg) {qr + 1, n, 1, 0}, 1: 0; 48 rig[o] = pcnt; 49 return ; 50 } 51 R int mid = l + r >> 1; 52 if (t <= mid) modify(o << 1, l, mid, t); 53 else modify(o << 1 | 1, mid + 1, r, t); 54 55 if (t == r) update(o, l, r); 56 } 57 void query(R int o, R int l, R int r) 58 { 59 if (ql <= l && r <= qr) 60 { 61 find(o, k, ans); 62 return ; 63 } 64 R int mid = l + r >> 1; 65 if (ql <= mid) query(o << 1, l, mid); 66 if (mid < qr) query(o << 1 | 1, mid + 1, r); 67 } 68 int main() 69 { 70 R int type; scanf("%d%d%d", &type, &n, &m); 71 for (R int i = 1; i <= n; ++i) scanf("%d", &x[i]); 72 R int Q; scanf("%d", &Q); 73 for (R int QQ = 1; QQ <= Q; ++QQ) 74 { 75 R int opt, l, r; scanf("%d%d%d", &opt, &l, &r); 76 type & 1 ? l ^= ans, r ^= ans : 0; 77 if (opt == 1) 78 { 79 scanf("%d%d", &ta, &tb); ++tnum; ql = l; qr = r; 80 modify(1, 1, Q, tnum); 81 } 82 else 83 { 84 scanf("%d", &k); type & 1 ? k ^= ans : 0; ql = l; qr = r; 85 ans = x[k]; 86 query(1, 1, Q); 87 printf("%d\n", ans); 88 } 89 } 90 return 0; 91 }

【UOJ #46】 【清華集訓2014】玄學