(建议您从上方链接进入我的个人网站查看此 Blog,在 Luogu 中图片会被墙掉,部分 Markdown 也会失效)
给定
首先二分答案很显然,二分
然后对于验证 我不会很显然,就不证明了。
The proof is left to the reader.
然后对于求
对于二分的范围,不难想到我们令数列中负数的和为
发现这个东西的复杂度是
显然我们发现这个转移时可以优化的,可以考虑写个平衡树然后区间取最大最小值等,但是我不会不好写,于是我们考虑线段树。
普通线段树显然开不下,所以我们要写一个动态开点的权值线段树,其中的叶子节点下标表示
对于权值线段树的范围,显然与二分限制相同。
那么最终复杂度为
xxxxxxxxxx
1131
2
3
4
5
6
7
8
9
10
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
23
24
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 初稿