P6859 蝴蝶与花 题解

P6859 蝴蝶与花 题解

题目大意:

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

  • 修改格式:(C i val)(a_i) 改为 (valin {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('
');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('
');
            else print(loc1+1),putchar(' '),print(R+loc1-1),putchar('
');
        }
        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;
}

原文地址:https://www.cnblogs.com/NuoCarter/p/15261766.html