Topic
Title Link: https://www.luogu.com.cn/problem/P4428
General idea of the topic
Count Reg n n n 0 / 1 0/1 0 / 1 string requires support
- Modify a location
- Find interval [ l , r ] [l,r] [l,r] how many sub interval rearranged binary numbers can be divided by three
1 ≤ n ≤ 1 0 5 1\leq n\leq 10^5 1≤n≤105
Problem solving ideas
First of all
2
2
k
%
3
=
1
(
k
∈
Z
)
2^{2k}\%3=1(k\in Z)
22k%3=1(k ∈ Z) and
2
2
k
+
1
%
3
=
2
(
k
∈
Z
)
2^{2k+1}\%3=2(k\in Z)
22k+1%3=2(k∈Z).
It is considered in three cases
- have 1 1 1 1 1 So obviously, it can't be divided by three in any case
- have 2 k 2k 2k 1 1 Then it would be nice if we were all at the bottom.
- have 2 k + 1 2k+1 2k+1 1 1 1( k k k cannot be 0 0 0), then there is a scheme to put a certain in an odd position 1 1 1 can be placed in the even position. At this time, the length of the interval needs to be at least 2 k + 3 2k+3 2k+3.
Then analyze it concretely, which is equivalent to an interval 1 1 The number of 1 cannot be 1 1 1 and if it is an odd number, there must be at least two 0 0 0.
It seems very complicated, which can be divided into the following situations
- The interval is all 1 1 1 and the length is odd
- There is one in the interval 0 0 0 and even length
- There is only one interval 1 1 1
- because 2 2 2 and 3 3 3 will repeat one, only one 1 1 1 and one 0 0 0, so this scheme needs to be added back
The fourth is the best maintenance. Just use the tree array to record
Then the first three we 0 / 1 0/1 One at 0 / 1 position s e t set set to query the predecessor / successor 0 / 1 of a location.
And then in the third case, we have 1 1 1 consider left and right 0 0 The 0 interval is then recorded in the tree array 1 1 Location of 1
For the second case, we consider for each 0 0 0 consider about 1 1 Then record it there 0 0 Location of 0
For the first case, we record the data at the leftmost end of the interval 0 0 0.
Then remember to consider the boundary when counting the answers
It's a little troublesome to write
Time complexity O ( n log n ) O(n\log n) O(nlogn)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<set> #define lowbit(x) (x&-x) #define ll long long using namespace std; const ll N=1e5+10; ll n,m,a[N],t[N],p[N]; set<ll> s[2]; void Change(ll x,ll val){ while(x<=n){ t[x]+=val; x+=lowbit(x); } return; } ll Ask(ll x){ ll ans=0; while(x){ ans+=t[x]; x-=lowbit(x); } return ans; } ll Left(ll op,ll x) {return (*--s[op].upper_bound(x));} ll Right(ll op,ll x) {return (*s[op].lower_bound(x));} ll Count(ll n) {return (n+1)/2*(n+2-(n&1))/2;} ll Caunt(ll n) {return n*(n+1)/2;} ll Calc(ll L,ll R) {return (L/2+1)*((R+1)/2)+((L+1)/2)*(R/2+1);} void Updata(ll x){ if(x<1||x>n)return; if(p[x])Change(x,-p[x]); if(a[x]){ ll L=(x-Left(1,x-1)-1),R=(Right(1,x+1)-x-1); p[x]=(L+1)*(R+1)-1; } else{ ll L=(x-Left(0,x-1)-1),R=(Right(0,x+1)-x-1); p[x]=Calc(L,R)+Count(R); } if(x<n&&a[x]!=a[x+1])p[x]--; Change(x,p[x]); return; } ll Get(ll x,ll l,ll r){ ll L=max(Left(0,x-1),l-1),R=min(Right(0,x+1),r+1); L=x-L-1;R=R-x-1; return Calc(L,R); } ll Qet(ll x,ll l,ll r){ ll L=max(Left(1,x-1),l-1),R=min(Right(1,x+1),r+1); L=x-L-1;R=R-x-1; return (L+1)*(R+1)-1; } signed main() { scanf("%lld",&n); s[0].insert(0);s[0].insert(n+1); s[1].insert(0);s[1].insert(n+1); for(ll i=1;i<=n;i++) scanf("%lld",&a[i]),s[a[i]].insert(i); for(ll i=1;i<=n;i++) Updata(i); scanf("%lld",&m); while(m--){ ll op,l,r,x; scanf("%lld",&op); if(op==1){ scanf("%lld",&x); s[a[x]].erase(x); a[x]=!a[x]; s[a[x]].insert(x); Updata(x); Updata(Left(0,x-1)); Updata(Left(1,x-1)); Updata(Right(0,x+1)); Updata(Right(1,x+1)); } else{ scanf("%lld%lld",&l,&r); ll ans=(r-l+1)*(r-l+2)/2; if(Left(1,r)<l){printf("%lld\n",ans);continue;} if(Left(0,r)<l){ans-=Count(r-l+1);printf("%lld\n",ans);continue;} ans-=Ask(r)-Ask(l-1); if(r<n&&a[r]!=a[r+1])ans--; ll Ll=Left(0,l-1),Rr=Right(0,r+1),Lr=Left(0,r),Rl=Right(0,l); ans=ans+Get(Rl,1,n)-Get(Rl,l,r); if(Lr!=Rl)ans=ans+Get(Lr,1,n)-Get(Lr,l,r); if(a[r+1])ans=ans+Count(Rr-Lr-1)-Count(r-Lr); if(a[l])ans=ans-Count(Rl-l); Ll=Left(1,l),Rr=Right(1,r),Lr=Left(1,r),Rl=Right(1,l); ans=ans+Qet(Rl,1,n)-Qet(Rl,l,r); if(Lr!=Rl)ans=ans+Qet(Lr,1,n)-Qet(Lr,l,r); // if(!a[r])ans=ans+Caunt(Rr-Rl-1)-Caunt(r-Rl); // if(!a[l])ans=ans-Caunt(Lr-l); printf("%lld\n",ans); } } return 0; }