P6859 蝴蝶与花 题解

P6859 蝴蝶与花 题解

题目大意:

给定一个长度为 \(n\) 的序列 \(a_i\) ,\(a_i\in \{ 1,2 \}\) ,每次操作给出两种类型的操作:

  • 修改格式:\(C \ i \ val\)\(a_i\) 改为 \(val\in \{1,2\}\)
  • 查询格式:\(A \ K\) ,查询整个序列有无一个子串和为 \(K\),输出所有方案中 \(L\) 最小的。

分析:

首先,设要求查询的和为 \(K\) ,首先当 \(K>sum||K=0\) 时是肯定无解的。(此时 \(sum\) 指整个序列的和)

因为要求左端点最小:

很容易想到从 \(1\) 开始,我们先找到以 \(1\) 为左端点,子串和 \(\geq K\) 的最小的右端点记作 \(R\)

这一点可以通过一个线段树上二分在 \(\Theta(\log n )\) 的时间解决,修改也就是一个简单的单点修改。

此时查询到的子串和一定为 \(K\)\(K+1\) ,这点可以通过反证法证明。

若子段和为 \(K\) 则证明已经找到了答案,着重解决的肯定是子段和为 \(K+1\) 的部分。

为了保证左端点最小,并且保持着当前的子串和为 \(K+1\) 不变,选择两个端点同时向右移动。

在两个端点向右移动的过程中,如果有一个端点的值为 \(1\) ,则找到了答案。

因为它们都从原本的 \(2\) 走到了 \(1\) 。(右端点的值一定为 \(2\)

而左端点可以近似的看作从 \(2\) 走到了 \(1\)

所以答案就是离左端点最近的 \(1\) ,或者右端点更近的 \(1\)

用一个 set 维护即可。

Code:

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
    x=0;char ch=getchar();bool f=false;
    while(!isdigit(ch)) f|=ch=='-',ch=getchar();
    while(isdigit(ch))  x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=f?-x:x;return;
}
template <typename T>
inline void print(T x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) print(x/10);
    putchar(x%10^48);return;
}
const int N=2e6+3,INF=1e9;
int n,m,a[N],nxt[N],pre[N];
struct node{
    int sum,lazy;
    #define sum(x)  c[x].sum
    #define lazy(x) c[x].lazy
}c[N<<2];
#define lc x<<1
#define rc x<<1|1
inline void Push_up(int x){sum(x)=sum(lc)+sum(rc);return;}
inline void Build(int x,int l,int r){
    if(l==r){sum(x)=a[l];return;}
    int mid=(l+r)>>1;Build(lc,l,mid),Build(rc,mid+1,r);
    Push_up(x);return;
}
inline void Modify(int x,int l,int r,int to,int d){
    if(l==r){sum(x)=d;return;}
    int mid=(l+r)>>1;if(mid>=to) Modify(lc,l,mid,to,d);
    else Modify(rc,mid+1,r,to,d);
    Push_up(x);return;
}
int res=0;
inline int Query(int x,int l,int r,int k){
    if(l==r){res+=a[l];return l;}
    int mid=(l+r)>>1;
    if(sum(lc)>=k)  return Query(lc,l,mid,k);
    else{res+=sum(lc);return Query(rc,mid+1,r,k-sum(lc));}
}
set<int> loc;
int main(){
    read(n),read(m);
    for(register int i=1;i<=n;++i){read(a[i]);if(a[i]==1) loc.insert(i);}
    Build(1,1,n);
    while(m--){
        char op[2];scanf("%s",op);
        if(op[0]=='A'){
            int x;read(x);
            if(x>sum(1)||x==0){puts("none");continue;}
            res=0;int R=Query(1,1,n,x);
            if(res==x){print(1),putchar(' '),print(R),putchar('\n');continue;}
            int loc1=INF,loc2=INF;
            if(!loc.empty())    loc1=*loc.begin();
            set<int>::iterator it=loc.lower_bound(R);
            if(it!=loc.end())   loc2=*it;
            int len=loc2-R+1;
            if(loc2==INF&&R+loc1-1>n){puts("none");continue;}
            if(loc1>=len) print(len),putchar(' '),print(loc2),putchar('\n');
            else print(loc1+1),putchar(' '),print(R+loc1-1),putchar('\n');
        }
        else{
            int i,val;read(i),read(val);
            if(a[i]==1) loc.erase(i);
            if(val==1)  loc.insert(i);
            a[i]=val;Modify(1,1,n,i,val);
        }
    }

    return 0;
}

posted @ 2021-09-13 11:39  NuoCarter  阅读(137)  评论(0编辑  收藏  举报