題解 「清華集訓2014」玄學
阿新 • • 發佈:2020-09-09
題目大意
給出一個 \(n\) 個點的序列,有 \(m\) 次操作,每次操作為以下兩種:
-
將 \(l\to r\) 的點都變為 \(ax+b\)
-
查詢在 \(l\to r\) 修改操作情況下序列第 \(k\) 個數是多少。
強制線上,\(n\le 10^5,m\le 6\times 10^5\)
思路
二進位制分組好啊!!!
跟普通的二進位制分組不太一樣,這道題查詢的一段區間的操作總和,所以我們自然而言地想到了線段樹,而且線段樹有一個好處,就是說每一段恰好就是 \(2^x\) 這種形態的,於是查詢的時候直接跟線上段樹查詢一樣地操作即可。
考慮修改操作,我們發現其實每次修改,都會有一段一段的區間是相同的變化規則,我們可以根據這個將兩個操作進行合併。
考慮時間複雜度,你每次增加的時候最多增加 \(3\) 段,於是總段數就是 \(n\log^2 n\),總時間複雜度也是 \(\Theta(n\log^2 n)\)(假設 \(n,m\) 同階)
\(\texttt{Code}\)
#include <bits/stdc++.h> using namespace std; #define Int register int #define MAXM 600005 #define MAXN 100005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int n,m,k,q,cnt,ans,kase,val[MAXN],lef[MAXM << 2],rig[MAXM << 2]; struct node{ int l,r,a,b;//表示l->r這段區間都變為ax+b node(){} node (int _l,int _r,int _a,int _b){l = _l,r = _r,a = _a,b = _b;} }p[MAXM * 200]; void Pushup (int x){ lef[x] = cnt + 1; for (Int i = lef[x << 1],j = lef[x << 1 | 1],las = 1;i <= rig[x << 1] || j <= rig[x << 1 | 1];) if (p[i].r <= p[j].r){ p[++ cnt] = node (las,p[i].r,1ll * p[i].a * p[j].a % m,(1ll * p[i].b * p[j].a % m + p[j].b) % m); las = p[i].r + 1; if (p[i].r == p[j].r) ++ i,++ j; else ++ i; } else{ p[++ cnt] = node (las,p[j].r,1ll * p[i].a * p[j].a % m,(1ll * p[i].b * p[j].a % m + p[j].b) % m); las = p[j].r + 1,++ j; } rig[x] = cnt; } void find (int x,int t,int &s){//在x維護的段內 int l = lef[x],r = rig[x]; while (l < r){ int mid = (l + r) >> 1; if (t <= p[mid].r) r = mid; else l = mid + 1; } s = (1ll * s * p[l].a % m + p[l].b) % m; } void Modify (int x,int l,int r,int pos,node &t){ if (l == r){ lef[x] = cnt + 1; if (t.l > 1) p[++ cnt] = node (1,t.l - 1,1,0); p[++ cnt] = t; if (t.r < n) p[++ cnt] = node (t.r + 1,n,1,0); rig[x] = cnt; return ; } int mid = (l + r) >> 1; if (pos <= mid) Modify (x << 1,l,mid,pos,t); else Modify (x << 1 | 1,mid + 1,r,pos,t); if (pos == r) Pushup (x); } void Query (int x,int l,int r,int ql,int qr){ if (ql <= l && r <= qr) return find (x,k,ans); int mid = (l + r) >> 1; if (ql <= mid) Query (x << 1,l,mid,ql,qr); if (qr > mid) Query (x << 1 | 1,mid + 1,r,ql,qr); } signed main(){ read (kase,n,m); for (Int i = 1;i <= n;++ i) read (val[i]); read (q);int tot = 0; for (Int i = 1;i <= q;++ i){ int opt,l,r;read (opt,l,r); if (kase & 1) l ^= ans,r ^= ans; if (opt == 1){ int ta,tb;read (ta,tb); node now = node (l,r,ta,tb); Modify (1,1,q,++ tot,now); } else{ read (k); if (kase & 1) k ^= ans; ans = val[k],Query (1,1,q,l,r); write (ans),putchar ('\n'); } } return 0; }