2025“钉耙编程”中国大学生算法设计暑期联赛(4)咖啡的罪恶

究极大烂场只能补这道了

首先要做的肯定有打标

我们能得len==4时有:

2 0 2 0

1 2 1 0

n==5有

2 1 2 0 0

当n>=7时,有 3 2 1 1 0 0 0

。。。。。。。

我们能发现如果想构成咖啡序列,那么有且只有:n-4 2 1 0 0 .......0 0 1 0 0 0

赛时我们想到是将整个线段压入线段树中然后每次访问的时候二分线段长度。

但这个思路其实访问的时候还是会回给卡成O(n),下面正解:

线段树维护的是区间的每个点作为起始点可以构成的咖啡序列长度的最大值,并且维护每个区间中左边界点最靠右的咖啡序列。

而对于序列的处理时,我们只需要将非0点的坐标直接插入一个飞天大set中,这样我们访问的时候可以以坐标为媒介,更方便的处理出序列中0个个数,只需要在set中查询其余非零位置即可

inl void update(int x) {
    if(x<=0) return;
    if(x+3<=n&&a[x]==2&&a[x+1]==0&&a[x+2]==2&&a[x+3]==0) {len[x]=4;change(1,1,n,x,4);return;}//特殊序列
    if(x+3<=n&&a[x]==1&&a[x+1]==2&&a[x+2]==1&&a[x+3]==0) {len[x]=4;change(1,1,n,x,4);return;}//特殊序列
    if(x+4<=n&&a[x]==2&&a[x+1]==1&&a[x+2]==2&&a[x+3]==0&&a[x+4]==0) {len[x]=5;change(1,1,n,x,5);return;}//特殊序列
    if(a[x]<=2) {len[x]=0;change(1,1,n,x,0);return;}//首位不符合要求
    if(x+3>n) {len[x]=0;change(1,1,n,x,0);return;}//首位位置不符合要求
    if(!(a[x+3]==0||(a[x]==3&&a[x+3]==1))) {len[x]=0;change(1,1,n,x,0);return;}
    //非第4位为0或者为3 2 1 0 0 0序列直接pass
    auto it=s.lower_bound(x+3);//二分找下一个pos
    int y=*it;
    if(it==s.end()) {len[x]=0;change(1,1,n,x,0);return;}
    //if(x==6) cout<<yan_jun<<endl;
    int len0=y-(x+2)-1;//计算0的个数
    if(y+3>n) {len[x]=0;change(1,1,n,x,0);return;}//后置1位置不符合

    if(len0==a[x]-3&&a[x+1]==2&&a[x+2]==1&&a[y]==1&&a[y+1]==0&&a[y+2]==0&&a[y+3]==0) {
        len[x]=a[x]+4;change(1,1,n,x,a[x]+4);return;
    }//可行序列,上面列过了
    len[x]=0;change(1,1,n,x,0);return;//剩下的直接pass
}

剩下比较烦入的就是修改时的联动修改了

首先当一个点修改的时候,如果他处于咖啡序列,那么需要更改此序列头部元素的属性

另外就是当他改为0的时候,首先因为特殊序列存在,要更改其前3位以及其本位,之后因为0在普通序列有两种位置,因此我们需要找到序列中在这个0两个非零位点并修改位点本身与位置-2(不要担心有没有必要多修改几个也无妨)

然后是1位置,先是本身与前两位的修改,再根据普通序列的特性找到1之前的非0位,然后update(pos-2)

之后是2位置,跟1差不多,但是根据普通序列最后要update(pos-1)

最后是都不符合的,直接修改本身就行

最后总Code:(真的提升代码能力)

#include<bits/stdc++.h>
#define ll long long
#define re register
#define inl inline
#define pii pair<int,int>
using namespace std;
inl int read() {
    int sum=0,f=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
    while(isdigit(c)) {sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
    return sum*f;
}
inl int ksm(int a,int b,int p) {
    int res=1;
    while(b) {
        if(b&1) res=res*a%p;
        b>>=1;
        a=a*a%p;
    }
    return res;
}
const int N=2e5+10;
int n,q,a[N];
struct node{
    int maxn,pos;
}tree[N<<2];
set<int> s;
inl void build(int k,int l,int r) {
    if(l==r) {
        tree[k].maxn=tree[k].pos=0;
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1,mid+1,r);
}
inl void pushup(int k) {
    tree[k].maxn=max(tree[k<<1].maxn,tree[k<<1|1].maxn);
    tree[k].pos=max(tree[k<<1].pos,tree[k<<1|1].pos);
}
inl void change(int k,int l,int r,int pos,int num) {
    if(l==r) {
        tree[k].maxn=num;
        if(num) tree[k].pos=l;
        else tree[k].pos=0;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) change(k<<1,l,mid,pos,num);
    if(pos>mid) change(k<<1|1,mid+1,r,pos,num);
    pushup(k);
}
inl int querymaxn(int k,int l,int r,int l1,int r1) {
    if(r1<l1) return 0;
    if(l1<=l&&r<=r1) {
        return tree[k].maxn;
    }
    int ans=0;
    int mid=(l+r)>>1;
    if(l1<=mid) ans=max(ans,querymaxn(k<<1,l,mid,l1,r1));
    if(r1>mid) ans=max(ans,querymaxn(k<<1|1,mid+1,r,l1,r1));
    return ans;
}
inl int querypos(int k,int l,int r,int l1,int r1){
    //cout<<l<<" "<<r<<endl;
    if(r1<l1) return 0;
    if(l1<=l&&r<=r1) {
        return tree[k].pos;
    }
    int ans=0;
    int mid=(l+r)>>1;
    if(l1<=mid) ans=max(ans,querypos(k<<1,l,mid,l1,r1));
    if(r1>mid) ans=max(ans,querypos(k<<1|1,mid+1,r,l1,r1));
    return ans;
}
int len[N];
inl void update(int x) {
    if(x<=0) return;
    if(x+3<=n&&a[x]==2&&a[x+1]==0&&a[x+2]==2&&a[x+3]==0) {len[x]=4;change(1,1,n,x,4);return;}
    if(x+3<=n&&a[x]==1&&a[x+1]==2&&a[x+2]==1&&a[x+3]==0) {len[x]=4;change(1,1,n,x,4);return;}
    if(x+4<=n&&a[x]==2&&a[x+1]==1&&a[x+2]==2&&a[x+3]==0&&a[x+4]==0) {len[x]=5;change(1,1,n,x,5);return;}
    if(a[x]<=2) {len[x]=0;change(1,1,n,x,0);return;}
    if(x+3>n) {len[x]=0;change(1,1,n,x,0);return;}
    if(!(a[x+3]==0||(a[x]==3&&a[x+3]==1))) {len[x]=0;change(1,1,n,x,0);return;}
    
    auto it=s.lower_bound(x+3);
    int y=*it;
    if(it==s.end()) {len[x]=0;change(1,1,n,x,0);return;}
    //if(x==6) cout<<yan_jun<<endl;
    int len0=y-(x+2)-1;
    if(y+3>n) {len[x]=0;change(1,1,n,x,0);return;}

    if(len0==a[x]-3&&a[x+1]==2&&a[x+2]==1&&a[y]==1&&a[y+1]==0&&a[y+2]==0&&a[y+3]==0) {
        len[x]=a[x]+4;change(1,1,n,x,a[x]+4);return;
    }//可行
    len[x]=0;change(1,1,n,x,0);return;
}
inl void solve() {
    n=read(),q=read();
    build(1,1,n);
    for(re int i=1;i<=n;i++) a[i]=read();
    for(re int i=1;i<=n;i++) {
        if(a[i]) s.insert(i);
    }
    for(re int i=1;i<=n;i++) update(i);
    //cout<<querypos(1,1,n,1,12)<<endl;
    while(q--) {
        int op=read();
        if(op==1) {
            int x=read(),y=read();
            if(a[x]) s.erase(x);
            a[x]=y;
            if(a[x]) s.insert(x);
            int pos=querypos(1,1,n,1,x);
            update(pos);
            if(a[x]==0) {
                update(x);
                update(x-1);
                update(x-2);
                update(x-3);
                auto it=s.lower_bound(x);
                if(it!=s.begin()) {
                    it--;
                    update(*it);
                    update((*it)-2);
                    if(it!=s.begin()) {
                        it--;
                        update(*it);
                        update((*it)-2);
                    }
                }
            }
            else if(a[x]==1) {
                update(x);
                update(x-1);
                update(x-2);
                auto it=s.lower_bound(x);
                if(it!=s.begin()){
                    it--;
                    update((*it)-2);
                }
            }
            else if(a[x]==2) {
                update(x);
                update(x-1);
                update(x-2);
                auto it=s.lower_bound(x);
                if(it!=s.begin()){
                    it--;
                    update((*it));
                }
            }
            else {
                update(x);
            }
        }
        else {
            int l=read(),r=read();
            int pos=querypos(1,1,n,1,r);
            //cout<<pos<<endl;
            if(pos+len[pos]-1>r) pos=querypos(1,1,n,1,pos-1);
            if(pos<l) puts("0");
            else printf("%d\n",querymaxn(1,1,n,l,pos));
        }
    }
    s.clear();
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T=read();
    while(T--) {
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值