BZOJ4447: [Scoi2015]小凸解密码(平衡树)

传送门

题解:
预处理所有 bi b i ,每次询问相当于修改单点,修改相当于修改两个点。

用平衡树维护所有0的位置,有连续的则合并。 找的时候直接找最接近 i+2n i + 2 n 的地方。 为了细节少一点,找到了之后暴力往两边挪动几位取min就可以了。

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
inline int rd() {
    char ch=getchar(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
    return i*f;
}
const int N=1e5+50,INF=0x3f3f3f3f;

typedef map <int,int> ::iterator it;
map <int,int> S;
int n,m,a[N],b[N],c[N];

inline int bef(int i) {return (i==1)?n:i-1;}
inline int nxt(int i) {return (i==n)?1:i+1;}
inline it bef(it p) {return --p;}
inline it nxt(it p) {return ++p;}
inline it getpos(int pos) {
    it p=--S.upper_bound(pos);
    if(p->first!=pos) {S[pos]=p->second; S[p->first]=pos-1; p=S.lower_bound(pos);}
    if(p->second!=pos) {S[pos+1]=p->second; S[pos]=pos;}
    return p;

}
inline void merge(int pos) {
    it p=--S.upper_bound(pos);
    while(bef(p)->first>0 && bef(p)->second==p->first-1) {p=bef(p); S[p->first]=pos; S.erase(nxt(p));}
    while(nxt(p)->first<=n && nxt(p)->first==p->second+1) {S[p->first]=nxt(p)->second; S.erase(nxt(p));}
}
int nowval[N];
inline void modify(int pos,int x) {
    if(nowval[pos]==0 && x) {
        it p=getpos(pos);
        S.erase(p);
    } else if(nowval[pos] && !x) {
        S[pos]=pos; 
        merge(pos);
    } nowval[pos]=x;
}
inline bool in(int l,int r,int pos) {
    if(l<=r) return l<=pos && pos<=r;
    else return pos<=r || pos>=l;
}
inline int calc_dis(int l,int r,int pos) {
    if(in(l,r,pos)) return 0;
    return min(min(abs(pos-l),abs(pos-r)),min(n-abs(pos-l),n-abs(pos-r)));
}
inline int query(int pos) {
    modify(pos,a[pos]); int ans=0;
    if(S.size()==2) {modify(pos,b[pos]); return -1;}
    it p=--S.upper_bound(pos+n/2>n?pos+n/2-n:pos+n/2);
    if(p==--S.end()) --p;
    if(p==S.begin()) ++p;
    for(int i=1;i<=3;i++) p=(p==++S.begin() ? --(--S.end()):--p); 
    for(int i=1;i<=8;i++) {
        int l=p->first,r=p->second;
        if(l!=1 && r==n) {
            it p2=++S.begin(); 
            if(p2->first==1)r=p2->second;
        }
        if(l==1 && r!=n) {
            it p2=--(--S.end());
            if(p2->second==n) l=p2->first;
        }
        ans=max(ans,calc_dis(l,r,pos));
        p=(p==--(--S.end())?++S.begin():++p);
    }
    modify(pos,b[pos]); 
    return ans;
}
int main() {
    n=rd(), m=rd();
    for(int i=1;i<=n;i++) a[i]=rd(), c[i]=(getchar()=='+')?0:1;
    for(int i=1;i<=n;i++) {
        if(c[i]==0) b[i]=(a[bef(i)]+a[i])%10;
        else b[i]=(a[bef(i)]*a[i])%10;
    }
    S[0]=0; S[n+1]=n+1;
    for(int i=1;i<=n;i++) 
        nowval[i]=1,modify(i,b[i]);
    for(int i=1;i<=m;i++) {
        int op=rd(), x=rd()+1;
        if(op==2) printf("%d\n",query(x));
        else {
            a[x]=rd(), c[x]=(getchar()=='+')?0:1;
            if(c[x]==0) b[x]=(a[bef(x)]+a[x])%10;
            else b[x]=(a[bef(x)]*a[x])%10;
            if(c[nxt(x)]==0) b[nxt(x)]=(a[x]+a[nxt(x)])%10;
            else b[nxt(x)]=(a[x]*a[nxt(x)])%10;
            modify(x,b[x]); modify(nxt(x),b[nxt(x)]);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值