#树状数组,倍增#洛谷 6859 蝴蝶与花
分析
考虑以第一个开头的前缀如果存在那么一定存在长度为\(s\)或\(s+1\)的路径和
那么要想消掉多去的1就得找到一个更短的连续2然后减去最近的1,这可以用树状数组单log维护
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=2000011;
int n,m,c[N],sum,a[N],two[21];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void update(int x,int y){for (;x<=n;x+=-x&x) c[x]+=y;}
inline signed query(int x){
rr int ans=0;
for (;x;x-=-x&x) ans+=c[x];
return ans;
}
inline signed answ(int s){
rr int ans=0,now=0;
for (rr int i=20;~i;--i)
if (ans+two[i]<=n&&now+c[ans+two[i]]<s)
ans+=two[i],now+=c[ans];
return ans+1;
}
inline signed get_two(int x){
rr int now=0,ans=0,t=query(x-1);
for (rr int i=20;~i;--i)
if (ans+two[i]<x||(ans+two[i]<=n&&now+c[ans+two[i]]-t==(ans+two[i]-x+1)*2))
ans+=two[i],now+=c[ans];
return ans;
}
signed main(){
n=iut(),m=iut(),two[0]=1;
for (rr int i=1;i<21;++i) two[i]=two[i-1]<<1;
for (rr int i=1;i<=n;++i) a[i]=iut(),c[i]=c[i-1]+a[i];
sum=c[n]; for (rr int i=n;i;--i) c[i]-=c[i&(i-1)];
for (rr int i=1;i<=m;++i){
rr char c=getchar();
while (!isalpha(c)) c=getchar();
if (c=='C'){
rr int x=iut(),y=iut();
update(x,y-a[x]),
sum+=y-a[x],a[x]=y;
}else{
rr int s=iut(),t,now;
if (!s||s>sum) {printf("none\n"); continue;}
t=answ(s),now=query(t);
if (now==s) {print(1),putchar(32),print(t),putchar(10); continue;}
rr int cnt1=get_two(1),cnt2=get_two(t)-t+1;
if (cnt1>=cnt2){
if (t+cnt2>n) printf("none\n");
else print(1+cnt2),putchar(32),print(t+cnt2),putchar(10);
}else{
if (t+cnt1>n) printf("none\n");
else print(2+cnt1),putchar(32),print(t+cnt1),putchar(10);
}
}
}
return 0;
}