补题日记[2022杭电暑期多校2]K-DOS Card
Posted cls1277
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了补题日记[2022杭电暑期多校2]K-DOS Card相关的知识,希望对你有一定的参考价值。
Pro
https://acm.hdu.edu.cn/showproblem.php?pid=7160
Sol
因为要求四个数正负组合的答案,又因为下标递增,因此只有两种符号分配情况++--
和+-+-
,针对这两种情况考虑如何维护出这种正负号组合。
将其拆分开就是+
,-
,++
,+-
,-+
,--
,+--
,++-
,+-+
,-+-
10种情况,左右线段树端点的组合刚好可以等于上面一个线段树的端点,即这么划分满足线段树的用法,因此使用线段树维护出这10个值与答案的两种情况,在pushup的时候进行从下往上更新。
易错点:因为线段树的非叶点更新时取子节点的最大值,因此这个端点初始化时应该为负数,而至于负数多少,需要提前计算(我测试使用-INT_MAX还不够,使用-1e18就对了。)
虽然此处在求答案时是左右相加,但是并不是平常意义上的相加或者取最大值,而是与pushup过程类似,相当于由两个查找的端点更新答案变量。因为可能存在使用两个线段树结点更新答案时会使答案更优的情况,这些情况都需要考虑到,而这种过程类似于pushup的过程,因此只需要用pushup的代码重载加号运算符即可(看代码)。
Code
//By cls1277
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define Fo(i,a,b) for(LL i=(a); i<=(b); i++)
#define Ro(i,b,a) for(LL i=(b); i>=(a); i--)
#define Eo(i,x,_) for(LL i=head[x]; i; i=_[i].next)
#define Ms(a,b) memset((a),(b),sizeof(a))
#define endl '\\n'
#define ls x<<1
#define rs x<<1|1
const LL maxn = 2e5+5;
LL n, q, a[maxn];
struct Seg
LL l, r;
LL ans1, ans2;//++-- +-+-
LL a[10];
//0 1 2 3 4 5 6 7 8 9
//+ - ++ +- -+ -- +-- ++- +-+ -+-
Seg()
ans1 = ans2 = -1e18;
Fo(i,0,9) a[i] = -1e18;
tree[maxn<<2];
Seg operator + (const Seg &x, const Seg &y)
Seg z;
Fo(i,0,9) z.a[i] = max(x.a[i], y.a[i]);
z.a[2] = max(z.a[2], x.a[0]+y.a[0]);
z.a[3] = max(z.a[3], x.a[0]+y.a[1]);
z.a[4] = max(z.a[4], x.a[1]+y.a[0]);
z.a[5] = max(z.a[5], x.a[1]+y.a[1]);
z.a[6] = max(z.a[6], x.a[0]+y.a[5], x.a[3]+y.a[1]);
z.a[7] = max(z.a[7], x.a[0]+y.a[3], x.a[2]+y.a[1]);
z.a[8] = max(z.a[8], x.a[0]+y.a[4], x.a[3]+y.a[0]);
z.a[9] = max(z.a[9], x.a[1]+y.a[3], x.a[4]+y.a[1]);
z.ans1 = max(x.ans1, y.ans1, x.a[0]+y.a[6], x.a[2]+y.a[5], x.a[7]+y.a[1]);
z.ans2 = max(x.ans2, y.ans2, x.a[0]+y.a[9], x.a[3]+y.a[3], x.a[8]+y.a[1]);
return z;
void pushup(LL x)
Fo(i,0,9) tree[x].a[i] = max(tree[ls].a[i], tree[rs].a[i]);
tree[x].a[2] = max(tree[x].a[2], tree[ls].a[0]+tree[rs].a[0]);
tree[x].a[3] = max(tree[x].a[3], tree[ls].a[0]+tree[rs].a[1]);
tree[x].a[4] = max(tree[x].a[4], tree[ls].a[1]+tree[rs].a[0]);
tree[x].a[5] = max(tree[x].a[5], tree[ls].a[1]+tree[rs].a[1]);
tree[x].a[6] = max(tree[x].a[6], tree[ls].a[0]+tree[rs].a[5], tree[ls].a[3]+tree[rs].a[1]);
tree[x].a[7] = max(tree[x].a[7], tree[ls].a[0]+tree[rs].a[3], tree[ls].a[2]+tree[rs].a[1]);
tree[x].a[8] = max(tree[x].a[8], tree[ls].a[0]+tree[rs].a[4], tree[ls].a[3]+tree[rs].a[0]);
tree[x].a[9] = max(tree[x].a[9], tree[ls].a[1]+tree[rs].a[3], tree[ls].a[4]+tree[rs].a[1]);
tree[x].ans1 = max(tree[ls].ans1, tree[rs].ans1, tree[ls].a[0]+tree[rs].a[6], tree[ls].a[2]+tree[rs].a[5], tree[ls].a[7]+tree[rs].a[1]);
tree[x].ans2 = max(tree[ls].ans2, tree[rs].ans2, tree[ls].a[0]+tree[rs].a[9], tree[ls].a[3]+tree[rs].a[3], tree[ls].a[8]+tree[rs].a[1]);
void build(LL x, LL l, LL r)
tree[x].l = l; tree[x].r = r;
tree[x].ans1 = tree[x].ans2 = -1e18;
Fo(i,0,9) tree[x].a[i] = -1e18;
if(l==r)
tree[x].a[0] = a[l];
tree[x].a[1] = -a[l];
return ;
LL mid = (l+r)>>1;
build(ls, l, mid);
build(rs, mid+1, r);
pushup(x);
Seg query(LL x, LL l, LL r)
if(l<=tree[x].l&&r>=tree[x].r) return tree[x];
LL mid = (tree[x].l+tree[x].r)>>1;
Seg res;
if(l<=mid) res = res+query(ls, l, r);
if(r>mid) res = res+query(rs, l, r);
return res;
int main()
ios::sync_with_stdio(false);
cin.tie(nullptr);
#ifdef DEBUG
freopen("data.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
LL t; cin>>t;
while(t--)
// Ms(tree, 0);
cin>>n>>q;
Fo(i,1,n)
cin>>a[i];
a[i] *= a[i];
build(1, 1, n);
while(q--)
LL l, r; cin>>l>>r;
Seg ans = query(1, l, r);
cout<<max(ans.ans1, ans.ans2)<<endl;
return 0;
以上是关于补题日记[2022杭电暑期多校2]K-DOS Card的主要内容,如果未能解决你的问题,请参考以下文章