专栏文章
题解:P14311 【MX-S8-T4】平衡三元组
P14311题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minhu21y
- 此快照首次捕获于
- 2025/12/02 02:39 3 个月前
- 此快照最后确认于
- 2025/12/02 02:39 3 个月前
前言
唯一一次以为可以场切的 T4,但是过程中
push_up 把懒标记抹掉了,又少判断了一种情况,查询又忘记 push_down 了,最终把正解 Hack 掉了。暴力的 push_down 又常数太大,两秒多的代码跑到了四秒,赛后还卡了好久的常……(论写法的重要性)
分析
Subtask 1
枚举每一个区间的 ,复杂度 。
Subtask 2
考虑固定一个点。考虑到不等式可以变形成 ,发现 和 其实等价,所以考虑固定点 ,左边寻找最大的 ,右边寻找最大的 。
这个听讲评的时候发现讲评用的是前缀后缀 ,但是我的代码用的是线段树,然后
push_down 写法常数太大被卡掉了。Subtask 3
,,也就是说没有修改操作。
这一个 Subtask 我一开始觉得是离线算法(莫队,整体二分),里面我觉得最正常的其实是莫队。然后看时限四秒,我觉得还是值得一试的。
考虑维护 表示 这个值里面的下标。
发现
这个是赛后看讲评才看到的, 里面必包含这个区间的最大值。
- 若 为最大值,则必须要有 和 也为最大值。
- 否则,最大值要么在 左,要么在 右,不论在哪一边,都会变成 或者 。
所以,从大往小遍历每一个 ,找出最大值(若最大值的个数大于等于三则直接返回),分别对该值为 和 计算贡献。
由于两种方法都是一样的,所以这里只说一种:
- 已知 为最大值,那么需要找的就是右边第一个可以作为 或者 的次大值,并考虑两种情况:
- 作为 时,则需要往右找 ,并判断。如果判断成功,则直接返回。
- 作为 时,在里面 里面找区间最大值贡献。
这就是这一个方法。虽然还没有写代码,也没有验证正确性,但不过这确实是通向正解的道路。
Subtask 4
不好意思,不知道怎么在 Subtask 3 上面继续优化。
讲评里面的说法好像是维护前 大值也可以,那么也说得过去,如果有大佬能够听明白希望能够私信本蒟蒻讲一下。
Subtask 5
单调不减,就是说选的数一定为 。其中, 一定为右端点,所以只需要考虑 就可以了。而且,发现我们只要取最靠近 的就好了。
既然有 ,那么直接先选择 ,尝试这一种。
- 如果成功,则直接返回。
- 否则,继续尝试?
尝试的次数可能很多,这是我当时想的。但不过看到了不等式之后,发现最坏情况有有 ,。
由于 最大 ,不会超过 ,最大只会失败 次,每一次失败往左移就可以了。
到了这里基本和正解无异了。
Subtask 6 & 7
不太懂设置这个的意义是什么,可能是用来分块或者 的。
Subtask 8
继承 Subtask 3 和 Subtask 5 的思想,发现可以优化成这个样子:
- 每一次失败跳掉左边的次大值。
- 因为 Subtask 5 有 和 必定相邻,所以还要考虑 和 之间取一个最大值判断,具体参考样例。
证明:
- 每一次失败取较左的最大值,是因为取左边非最大值不仅可能值域比这个小,还有可能使得式子不成立。值域变大的情况可以由左边最大值的左边最大值一直递归包含,固考虑每一个最大值的断点即可。
- 在 和 中只需要考虑取最大值即可,不用考虑因为最大值使得其不成立的情况。令 为 中最大值,即使有 ,也可能会有 前一次递归时有 作为该 的情况并已经计算了贡献。
所以查询时间复杂度为 ,修改复杂度为 ,总时间复杂度有最劣 。
CPP#include<stdio.h>
#include<ctype.h>
#define MAXN 1000010
#define lson root<<1
#define rson root<<1|1
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#define Opt optimize
#define tar target
#pragma GCC Opt(3)
#pragma GCC tar("avx")
#pragma GCC Opt("Ofast")
#pragma GCC Opt("inline")
#pragma GCC Opt("-fgcse")
#pragma GCC Opt("-fgcse-lm")
#pragma GCC Opt("-fipa-sra")
#pragma GCC Opt("-ftree-pre")
#pragma GCC Opt("-ftree-vrp")
#pragma GCC Opt("-fpeephole2")
#pragma GCC Opt("-ffast-math")
#pragma GCC Opt("-fsched-spec")
#pragma GCC Opt("unroll-loops")
#pragma GCC Opt("-falign-jumps")
#pragma GCC Opt("-falign-loops")
#pragma GCC Opt("-falign-labels")
#pragma GCC Opt("-fdevirtualize")
#pragma GCC Opt("-fcaller-saves")
#pragma GCC Opt("-fcrossjumping")
#pragma GCC Opt("-fthread-jumps")
#pragma GCC Opt("-funroll-loops")
#pragma GCC Opt("-fwhole-program")
#pragma GCC Opt("-freorder-blocks")
#pragma GCC Opt("-fschedule-insns")
#pragma GCC Opt("inline-functions")
#pragma GCC Opt("-ftree-tail-merge")
#pragma GCC Opt("-fschedule-insns2")
#pragma GCC Opt("-fstrict-aliasing")
#pragma GCC Opt("-fstrict-overflow")
#pragma GCC Opt("-falign-functions")
#pragma GCC Opt("-fcse-skip-blocks")
#pragma GCC Opt("-fcse-follow-jumps")
#pragma GCC Opt("-fsched-interblock")
#pragma GCC Opt("-fpartial-inlining")
#pragma GCC Opt("no-stack-protector")
#pragma GCC Opt("-freorder-functions")
#pragma GCC Opt("-findirect-inlining")
#pragma GCC Opt("-fhoist-adjacent-loads")
#pragma GCC Opt("-frerun-cse-after-loop")
#pragma GCC Opt("inline-small-functions")
#pragma GCC Opt("-finline-small-functions")
#pragma GCC Opt("-ftree-switch-conversion")
#pragma GCC Opt("-foptimize-sibling-calls")
#pragma GCC Opt("-fexpensive-optimizations")
#pragma GCC Opt("-funsafe-loop-optimizations")
#pragma GCC Opt("inline-functions-called-once")
#pragma GCC Opt("-fdelete-null-pointer-checks")
#pragma GCC Opt(2)
typedef long long ll;
const ll INF=1e17;
struct node{
int tag,pos;
ll maxi;
node(int pos=0,ll maxi=-INF){
this->tag=0;
this->pos=pos;
this->maxi=maxi;
}
}tree[MAXN<<2];
char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;
inline ll max(const ll a,const ll b){
return a>b?a:b;
}
inline int read(){
register int res=0,f=1;
register char c=getchar();
while(!isdigit(c)){
if(c=='-'){
f=-1;
}
c=getchar();
}
while(isdigit(c)){
res=(res<<1)+(res<<3)+(c^48);
c=getchar();
}
return res*f;
}
inline node merge(const node &a,const node &b){
if(a.maxi>b.maxi){
return a;
}
return b;
}
inline void push_up(int root){
const int tag=tree[root].tag;
tree[root]=merge(tree[lson],tree[rson]);
tree[root].tag=tag;
}
inline void push_down(int root){
tree[lson].tag+=tree[root].tag;
tree[rson].tag+=tree[root].tag;
tree[lson].maxi+=tree[root].tag;
tree[rson].maxi+=tree[root].tag;
tree[root].tag=0;
// printf("%d %d\n",tree[lson].maxi,tree[rson].maxi);
}
inline void build(int root,int l,int r){
if(l==r){
tree[root].maxi=read();
tree[root].pos=l;
return;
}
const int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
push_up(root);
}
inline void change(const int root,const int l,const int r,const int L,const int R,const int tag){
if(L<=l&&r<=R){
tree[root].tag+=tag;
tree[root].maxi+=tag;
return;
}
push_down(root);
const int mid=(l+r)>>1;
if(L<=mid){
change(lson,l,mid,L,R,tag);
}
if(mid<R){
change(rson,mid+1,r,L,R,tag);
}
push_up(root);
}
inline node query(int root,int l,int r,int L,int R){
if(L<=l&&r<=R){
return tree[root];
}
// printf("%d %d\n",l,r);
push_down(root);
const int mid=(l+r)>>1;
if(L>mid){
return query(rson,mid+1,r,L,R);
}
if(mid>=R){
return query(lson,l,mid,L,R);
}
return merge(query(lson,l,mid,L,R),query(rson,mid+1,r,L,R));
}
inline void print(const int root,const int l,const int r){
if(l==r){
printf("[%d]:%lld\n",l,tree[root].maxi);
return;
}
push_down(root);
printf("[%d,%d]:%lld\n",l,r,tree[root].maxi);
const int mid=(l+r)>>1;
print(lson,l,mid);
print(rson,mid+1,r);
}
int main(){
const int n=read();
register int q=read();
build(1,1,n);
while(q--){
const int opt=read(),l=read(),r=read();
if(opt==1){
ll ans=-INF;
node x,z=query(1,1,n,l,r);
node y=node(z.pos,INF);
while(y.pos>l){
x=query(1,1,n,l,y.pos-1);
if(x.maxi+z.maxi>=(y.maxi<<1)){
ans=max(ans,x.maxi+y.maxi+z.maxi);
break;
}
if(x.pos<y.pos-1){
ans=max(ans,x.maxi+z.maxi+query(1,1,n,x.pos+1,y.pos-1).maxi);
}
y=x;
}
x=z;
y=node(x.pos,INF);
while(y.pos<r){
z=query(1,1,n,y.pos+1,r);
if(x.maxi+z.maxi>=(y.maxi<<1)){
ans=max(ans,x.maxi+y.maxi+z.maxi);
break;
}
if(y.pos<z.pos-1){
ans=max(ans,x.maxi+z.maxi+query(1,1,n,y.pos+1,z.pos-1).maxi);
}
y=z;
}
if(ans==-INF){
puts("No");
}else{
printf("%lld\n",ans);
}
}else{
change(1,1,n,l,r,read());
}
// print(1,1,n);
// putchar('\n');
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...