日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[国家集训队]middle

發(fā)布時間:2023/12/18 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [国家集训队]middle 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

嘟嘟嘟

有誰能想到這題會用到主席樹呢?(不愧是WJMZBMR出的題)

首先考慮如果區(qū)間是固定的話,中位數(shù)該怎么求。
沒錯,二分。如果大于當(dāng)前二分值\(mid\)的數(shù)比小于\(mid\)的數(shù)多,說明\(mid\)還可以再變大,向右二分;否則向左二分。
如果我們把小于\(mid\)的數(shù)都標(biāo)記成\(-1\),大于的標(biāo)記成\(1\),那么只用判斷這個區(qū)間的和是否\(\geqslant 0\)就行了。

但現(xiàn)在區(qū)間不固定。首先\([b + 1, c - 1]\)是一定要選的。對于\([a, b]\)\([c, d]\),因為要讓中位數(shù)盡量大,所以應(yīng)該選\([a, b]\)的最大后綴和以及\([c, d]\)的最大前綴和。

主要思路就是這些,但單次查詢的復(fù)雜度是\(O(n \log{n})\)的,過不了。得想辦法優(yōu)化。

如果對每一個二分的值建一棵區(qū)間線段樹(這里的二分在序列中的值中進(jìn)行就行,而不是\(1\)\(1e9\),所以只用建\(n\)棵),把小于他的都標(biāo)記成\(1\),大于標(biāo)記成\(-1\),那么每一次查詢就能達(dá)到\(O(\log ^ 2{n})\)了。
但是很顯然這樣空間開不下,而且預(yù)處理復(fù)雜度過高。所以現(xiàn)在得想辦法減少預(yù)處理的時間。
如果把序列中的數(shù)排一個序,會發(fā)現(xiàn)對于相鄰的兩個不一樣的數(shù)(因為數(shù)字可能有重),建的線段樹只有一處不一樣,而這一處不一樣只會導(dǎo)致線段樹中的一條鏈改變。所以我們只要單獨把這條鏈提建出來就行了。
然后就會發(fā)現(xiàn)這其實就是一棵主席樹呀。

于是這題就寫完了。

#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<cstring> #include<cstdlib> #include<cctype> #include<vector> #include<stack> #include<queue> using namespace std; #define enter puts("") #define space putchar(' ') #define Mem(a, x) memset(a, x, sizeof(a)) #define rg register typedef long long ll; typedef double db; const int INF = 0x3f3f3f3f; const db eps = 1e-8; const int maxn = 2e4 + 5; const int maxt = 2e6 + 5; inline ll read() {ll ans = 0;char ch = getchar(), last = ' ';while(!isdigit(ch)) {last = ch; ch = getchar();}while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();}if(last == '-') ans = -ans;return ans; } inline void write(ll x) {if(x < 0) x = -x, putchar('-');if(x >= 10) write(x / 10);putchar(x % 10 + '0'); }int n, _n, m, a[maxn], b[maxn], q[4]; vector<int> v[maxn];struct Tree {int ls, rs;int sum, lmax, rmax; }t[maxt]; int root[maxn], cnt = 0; void pushup(int now) {t[now].sum = t[t[now].ls].sum + t[t[now].rs].sum;t[now].lmax = max(t[t[now].ls].lmax, t[t[now].ls].sum + t[t[now].rs].lmax);t[now].rmax = max(t[t[now].rs].rmax, t[t[now].rs].sum + t[t[now].ls].rmax); } void build(int& now, int l, int r) {if(!now) now = ++cnt;if(l == r) {t[now].sum = t[now].lmax = t[now].rmax = 1; return;}int mid = (l + r) >> 1;build(t[now].ls, l, mid);build(t[now].rs, mid + 1, r);pushup(now); } void insert(int old, int& now, int l, int r, int id) {t[now = ++cnt] = t[old];if(l == r) {t[now].sum = t[now].lmax = t[now].rmax = -1; return;}int mid = (l + r) >> 1;if(id <= mid) insert(t[old].ls, t[now].ls, l, mid, id);else insert(t[old].rs, t[now].rs, mid + 1, r, id);pushup(now); } int querySum(int now, int l, int r, int L, int R) {if(R < L) return 0;if(l == L && r == R) return t[now].sum;int mid = (l + r) >> 1;if(R <= mid) return querySum(t[now].ls, l, mid, L, R);else if(L > mid) return querySum(t[now].rs, mid + 1, r, L, R);else return querySum(t[now].ls, l, mid, L, mid) + querySum(t[now].rs, mid + 1, r, mid + 1, R); } int queryL(int now, int l, int r, int L, int R) {if(l == L && r == R) return t[now].lmax;int mid = (l + r) >> 1;if(R <= mid) return queryL(t[now].ls, l, mid, L, R);else if(L > mid) return queryL(t[now].rs, mid + 1, r, L, R);else{int ret1 = queryL(t[now].ls, l, mid, L, mid);int ret2 = querySum(t[now].ls, l, mid, L, mid) + queryL(t[now].rs, mid + 1, r, mid + 1, R);return max(ret1, ret2);} } int queryR(int now, int l, int r, int L, int R) {if(l == L && r == R) return t[now].rmax;int mid = (l + r) >> 1;if(R <= mid) return queryR(t[now].ls, l, mid, L, R);else if(L > mid) return queryR(t[now].rs, mid + 1, r, L, R);else{int ret1 = queryR(t[now].rs, mid + 1, r, mid + 1, R);int ret2 = querySum(t[now].rs, mid + 1, r, mid + 1, R) + queryR(t[now].ls, l, mid, L, mid);return max(ret1, ret2);} }bool judge(int x) {int ans1 = querySum(root[x], 1, n, q[1] + 1, q[2] - 1);int ans2 = queryR(root[x], 1, n, q[0], q[1]);int ans3 = queryL(root[x], 1, n, q[2], q[3]);return ans1 + ans2 + ans3 >= 0; } int solve() {int L = 1, R = _n;while(L < R){int mid = (L + R + 1) >> 1;if(judge(mid)) L = mid;else R = mid - 1;}return L; }int main() {n = read();build(root[0], 1, n);for(int i = 1; i <= n; ++i) a[i] = b[i] = read();sort(b + 1, b + n + 1);_n = unique(b + 1, b + n + 1) - b - 1;for(int i = 1; i <= n; ++i){a[i] = lower_bound(b + 1, b + _n + 1, a[i]) - b;v[a[i]].push_back(i);}for(int i = 1; i <= _n; ++i){root[i] = root[i - 1];for(int j = 0; j < (int)v[i - 1].size(); ++j)insert(root[i], root[i], 1, n, v[i - 1][j]);}m = read();for(int i = 1, ans = 0; i <= m; ++i){for(int j = 0; j < 4; ++j) q[j] = read();for(int j = 0; j < 4; ++j) q[j] = (q[j] + ans) % n + 1;sort(q, q + 4);ans = b[solve()];write(ans), enter;}return 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/mrclr/p/10074763.html

總結(jié)

以上是生活随笔為你收集整理的[国家集训队]middle的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。