您的位置:首页 > 其它

【分块】bzoj1858 [Scoi2010]序列操作

2014-10-23 15:26 267 查看
分块 Or 线段树 分块的登峰造极之题

每块维护8个值:

包括左端点在内的最长1段;

包括右端点在内的最长1段;

该块内的最长1段;

该块内1的个数;

包括左端点在内的最长0段;//这四个是因为可能有翻转操作,需要swap 0有关的标记 和 1有关的标记

包括右端点在内的最长0段;

该块内的最长0段;

该块内0的个数。

2个懒标记:是否翻转,覆盖成了什么。

怎么处理一个块上有两个标记的情况呢?

若该块原来没有任何标记,或要打的标记和原本的标记种类相同,则直接打上标记;

若已有翻转标记,再覆盖时则先清除翻转标记,再打上覆盖标记;

若已有覆盖标记,再翻转时,则直接将覆盖标记取反。

So 某个块上同时只会有1个标记。

代码能力题,同样无法体现分块相对于线段树的“代码简介优势”,不推荐写。耗时也多于线段树。

P.S.注意取最长段的时候的细节……如下代码中高亮部分。

P.S.P.S.注意Pushdown的时机。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int len[400],lenl[400],lenr[400],n,m,l[400],r[400],num[100001],sum,sz,x,y;
bool a[100001];
int len0[400],lenl0[400],lenr0[400],sum1[400],sum0[400];
int delta[400],op;
bool Spin[400];
int Res,Num;char C,CH[12];
inline int G()
{
Res=0;C='*';
while(C<'0'||C>'9')C=getchar();
while(C>='0'&&C<='9'){Res=Res*10+(C-'0');C=getchar();}
return Res;
}
inline void P(long long x)
{
Num=0;if(!x){putchar('0');puts("");return;}
while(x>0)CH[++Num]=x%10,x/=10;
while(Num)putchar(CH[Num--]+48);
puts("");
}
void Pushdown(const int &p)
{
if(delta[p]!=-1)
{
for(int i=l[p];i<=r[p];i++) a[i]=delta[p];
delta[p]=-1;
}
else if(Spin[p])
{
for(int i=l[p];i<=r[p];i++) a[i]^=1;
Spin[p]=false;
}
}
inline void Work(const int &Lb,const int &Rb,const int &sym)
{
if(sym==0||sym==1) {for(int i=Lb;i<=Rb;i++) a[i]=sym;}
else if(sym==2) {for(int i=Lb;i<=Rb;i++) a[i]^=1;}
int cnt=0;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++) {if(a[i]) break; cnt++;}//暴力lenl0
lenl0[num[Lb]]=cnt; cnt=0;
for(int i=r[num[Lb]];i>=l[num[Lb]];i--) {if(a[i]) break; cnt++;}//暴力lenr0
lenr0[num[Lb]]=cnt; cnt=0;
int Longest=0;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++)//暴力len0
{
if(a[i]) cnt=0; else cnt++;
if(cnt>Longest) Longest=cnt;
}
len0[num[Lb]]=Longest; cnt=0;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++) {if(!a[i]) break; cnt++;}//暴力lenl
lenl[num[Lb]]=cnt; cnt=0;
for(int i=r[num[Lb]];i>=l[num[Lb]];i--) {if(!a[i]) break; cnt++;}//暴力lenr
lenr[num[Lb]]=cnt; cnt=0; Longest=0;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++)//暴力len
{
if(!a[i]) cnt=0; else cnt++;
if(cnt>Longest) Longest=cnt;
}
len[num[Lb]]=Longest; cnt=0;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++) if(a[i]) cnt++;//暴力sum1
sum1[num[Lb]]=cnt; cnt=0;
for(int i=l[num[Lb]];i<=r[num[Lb]];i++) if(!a[i]) cnt++;//暴力sum0
sum0[num[Lb]]=cnt;
}
void makeblock()
{
memset(delta,-1,sizeof(delta));
sz=sqrt((double)n*0.5);
for(sum=1;sum*sz<n;sum++)
{
l[sum]=(sum-1)*sz+1;
r[sum]=sum*sz;
for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
Work(l[sum],r[sum],-1);
}
l[sum]=sz*(sum-1)+1; r[sum]=n;
for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
Work(l[sum],r[sum],-1);
}
inline void Update(const int &L,const int &R,const bool &sym)
{
Pushdown(num[L]);
Pushdown(num[R]);
if(num[L]==num[R]) Work(L,R,sym);
else
{
Work(L,r[num[L]],sym);
Work(l[num[R]],R,sym);
for(int i=num[L]+1;i<num[R];i++)
{
if(Spin[i]) Spin[i]=false; delta[i]=sym;
len[i]=lenl[i]=lenr[i]=sum1[i]=sym ? r[i]-l[i]+1 : 0;
len0[i]=lenl0[i]=lenr0[i]=sum0[i]=sym ? 0 : r[i]-l[i]+1;
}
}
}
inline void Update_Spin(const int &L,const int &R)
{
Pushdown(num[L]);
Pushdown(num[R]);
if(num[L]==num[R]) Work(L,R,2);
else
{
Work(L,r[num[L]],2);
Work(l[num[R]],R,2);
for(int i=num[L]+1;i<num[R];i++)
{
if(delta[i]==-1) Spin[i]^=1; else delta[i]^=1;
swap(sum1[i],sum0[i]);
swap(len[i],len0[i]);
swap(lenl[i],lenl0[i]);
swap(lenr[i],lenr0[i]);
}
}
}
inline void Query_Sum(const int &L,const int &R)
{
int ans=0;
Pushdown(num[L]);
Pushdown(num[R]);
if(num[L]==num[R]) {for(int i=L;i<=R;i++) if(a[i]) ans++;}
else
{
for(int i=L;i<=r[num[L]];i++) if(a[i]) ans++;
for(int i=l[num[R]];i<=R;i++) if(a[i]) ans++;
for(int i=num[L]+1;i<num[R];i++) ans+=sum1[i];
}
P(ans);
}
135 inline void Query_Len(const int &L,const int &R)
136 {
137     Pushdown(num[L]);
138     Pushdown(num[R]);
139     int ans=0,cnt=0;
140     if(num[L]==num[R])
141       {
142           for(int i=L;i<=R;i++)
143             {
144                 if(a[i]) cnt++; else cnt=0;
145                 ans=max(ans,cnt);
146             }
147           P(ans);
148       }
149     else
150       {
151           int kua=0,cntr=0;
152         for(int i=r[num[L]];i>=L;i--) {if(!a[i]) break; kua++;}
153         for(int i=l[num[R]];i<=R;i++) {if(!a[i]) break; cntr++;}
154         for(int i=num[L]+1;i<num[R];i++)
155           {
156               if(kua) kua+=lenl[i];
157             ans=max(ans,kua);
158               if(len[i]!=r[i]-l[i]+1) kua=0;
159             if(!kua&&lenr[i]) kua=lenr[i];
160             ans=max(ans,len[i]);
161           }
162           for(int i=L;i<=r[num[L]];i++)
163             {
164                 if(a[i]) cnt++; else cnt=0;
165                 ans=max(ans,cnt);
166             } cnt=0;
167           for(int i=l[num[R]];i<=R;i++)
168             {
169                 if(a[i]) cnt++; else cnt=0;
170                 ans=max(ans,cnt);
171             }
172         P(max(ans,kua+cntr));
173       }
174 }
 int main()
{
n=G();m=G();
for(int i=1;i<=n;i++) a[i]=G();
makeblock();
for(int i=1;i<=m;i++)
{
op=G();x=G();y=G();x++;y++;
if(op==0) Update(x,y,0);
else if(op==1) Update(x,y,1);
else if(op==2) Update_Spin(x,y);
else if(op==3) Query_Sum(x,y);
else Query_Len(x,y);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: