(建议您从上方链接进入我的个人网站查看此 Blog,在 Luogu 中图片会被墙掉,部分 Markdown 也会失效)
给定
首先二分答案很显然,二分
然后对于验证 我不会很显然,就不证明了。
The proof is left to the reader.
然后对于求
对于二分的范围,不难想到我们令数列中负数的和为
发现这个东西的复杂度是
显然我们发现这个转移时可以优化的,可以考虑写个平衡树然后区间取最大最小值等,但是我不会不好写,于是我们考虑线段树。
普通线段树显然开不下,所以我们要写一个动态开点的权值线段树,其中的叶子节点下标表示
对于权值线段树的范围,显然与二分限制相同。
那么最终复杂度为
xxxxxxxxxx113123
45678910
11using namespace std;12using namespace __gnu_pbds;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
2324
25template<typename T = int>26inline T read(void);27
28struct Node{29 Node *ls, *rs;30 int fmn, fmx;31 OPNEW;32}nd[30000000];33void* Node::operator new(size_t){static Node* P = nd; return P++;}34int limMin, limMax;35int N, K;36int a[18000];37int sum[18000];38int fmn[18000], fmx[18000];39Node* rt;40class SegTree{41 private:42 43 44 public:45 void Pushup(Node* p){46 if(!p)return;47 p->fmn = min(p->ls ? p->ls->fmn : INF, p->rs ? p->rs->fmn : INF),48 p->fmx = max(p->ls ? p->ls->fmx : -INF, p->rs ? p->rs->fmx : -INF);49 }50 void Modify(int idx, pair < int, int > val, Node* &p = rt, int gl = limMin, int gr = limMax){51 if(!p)p = new Node{npt, npt, INF, 0};52 if(gl == gr)return tie(p->fmn, p->fmx) = val, void();53 if(idx <= MID) Modify(idx, val, p->ls, gl, MID);54 else Modify(idx, val, p->rs, MID + 1, gr);55 Pushup(p);56 }57 pair < int, int > Query(int l, int r, Node* p = rt, int gl = limMin, int gr = limMax){58 // printf("Querying l = %d, r = %d, gl = %d, gr = %d, val = %d,%d\n", l, r, gl, gr, p ? p->fmn : -114514, p ? p->fmx : 114514);59 if(!p)return {INF, -INF};60 if(l <= gl && gr <= r)return {p->fmn, p->fmx};61 auto L = MID >= l ? Query(l, r, p->ls, gl, MID) : make_pair(INF, -INF);62 auto R = MID + 1 <= r ? Query(l, r, p->rs, MID + 1, gr) : make_pair(INF, -INF);63 return {min(L.first, R.first), max(L.second, R.second)};64 }65}st;66bool Check(int M){67 rt = new Node{npt, npt, INF, -INF};68 fmx[0] = fmn[0] = 0;69 st.Modify(sum[0], {fmn[0], fmx[0]});70 for(int i = 1; i <= N; ++i){71 tie(fmn[i], fmx[i]) = st.Query(sum[i] - M, INF);72 ++fmn[i], ++fmx[i];73 st.Modify(sum[i], {fmn[i], fmx[i]});74 }75 if(fmn[N] <= K && K <= fmx[N])return true;76 return false;77}78int main(){79 int T = read();80 while(T--){81 limMin = limMax = 0;82 N = read(), K = read();83 for(int i = 1; i <= N; ++i)84 a[i] = read(),85 a[i] >= 0 ? limMax += a[i] : limMin += a[i],86 sum[i] = sum[i - 1] + a[i];87 int l = limMin, r = limMax, ans(-1);88 while(l <= r){89 int mid = (l + r) >> 1;90 if(Check(mid))ans = mid, r = mid - 1;91 else l = mid + 1;92 }93 printf("%d\n", ans);94 }95 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);96 return 0;97}98
99template<typename T>100inline T read(void){101 T ret(0);102 short flag(1);103 char c = getchar();104 while(c != '-' && !isdigit(c))c = getchar();105 if(c == '-')flag = -1, c = getchar();106 while(isdigit(c)){107 ret *= 10;108 ret += int(c - '0');109 c = getchar();110 }111 ret *= flag;112 return ret;113}update-2022_10_13 初稿