[SCOI2010]序列操作[分块or线段树]
#include<cstdio>
#include<iostream>
#define lc k<<1
#define rc k<<1|1
using namespace std;
const int N=1e5+;
int n,m,a[N];
struct sgt{
int sum,tag,rev,max1,max0,lss0,rss0,lss1,rss1,lp,rp,l,r;
}s,tr[N<<];
inline int read(){
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
sgt merge(sgt left,sgt right){
sgt now;
now.lp=left.lp;
now.rp=right.rp;
now.sum=left.sum+right.sum; now.lss0=left.lss0;
now.rss0=right.rss0;
if(!right.lp&&!left.sum) now.lss0=max(now.lss0,left.r-left.l++right.lss0);
if(!left.rp&&!right.sum) now.rss0=max(now.rss0,right.r-right.l++left.rss0);
now.max0=max(left.max0,right.max0);
if(!left.rp&&!right.lp) now.max0=max(now.max0,left.rss0+right.lss0); now.lss1=left.lss1;
now.rss1=right.rss1;
if(right.lp&&left.sum==left.r-left.l+) now.lss1=max(now.lss1,left.sum+right.lss1);
if(left.rp&&right.sum==right.r-right.l+) now.rss1=max(now.rss1,right.sum+left.rss1);
now.max1=max(left.max1,right.max1);
if(left.rp&&right.lp) now.max1=max(now.max1,left.rss1+right.lss1);
return now;
}
void updata(int k){
tr[k].lp=tr[lc].lp;
tr[k].rp=tr[rc].rp;
tr[k].sum=tr[lc].sum+tr[rc].sum; tr[k].lss0=tr[lc].lss0;
tr[k].rss0=tr[rc].rss0;
if(!tr[rc].lp&&!tr[lc].sum) tr[k].lss0=max(tr[k].lss0,tr[lc].r-tr[lc].l++tr[rc].lss0);
if(!tr[lc].rp&&!tr[rc].sum) tr[k].rss0=max(tr[k].rss0,tr[rc].r-tr[rc].l++tr[lc].rss0);
tr[k].max0=max(tr[lc].max0,tr[rc].max0);
if(!tr[lc].rp&&!tr[rc].lp) tr[k].max0=max(tr[k].max0,tr[lc].rss0+tr[rc].lss0); tr[k].lss1=tr[lc].lss1;
tr[k].rss1=tr[rc].rss1;
if(tr[rc].lp&&tr[lc].sum==tr[lc].r-tr[lc].l+) tr[k].lss1=max(tr[k].lss1,tr[lc].sum+tr[rc].lss1);
if(tr[lc].rp&&tr[rc].sum==tr[rc].r-tr[rc].l+) tr[k].rss1=max(tr[k].rss1,tr[rc].sum+tr[lc].rss1);
tr[k].max1=max(tr[lc].max1,tr[rc].max1);
if(tr[lc].rp&&tr[rc].lp) tr[k].max1=max(tr[k].max1,tr[lc].rss1+tr[rc].lss1);
}
void pushdown(int k){
if(~tr[k].tag){
// tr[k].rev=0;
if(tr[k].tag){
tr[lc].lp=tr[lc].rp=;
tr[lc].lss1=tr[lc].rss1=tr[lc].max1=tr[lc].sum=tr[lc].r-tr[lc].l+;
tr[lc].lss0=tr[lc].rss0=tr[lc].max0=; tr[rc].lp=tr[rc].rp=;
tr[rc].lss1=tr[rc].rss1=tr[rc].max1=tr[rc].sum=tr[rc].r-tr[rc].l+;
tr[rc].lss0=tr[rc].rss0=tr[rc].max0=;
}
else{
tr[lc].lp=tr[lc].rp=;
tr[lc].lss1=tr[lc].rss1=tr[lc].max1=tr[lc].sum=;
tr[lc].lss0=tr[lc].rss0=tr[lc].max0=tr[lc].r-tr[lc].l+; tr[rc].lp=tr[rc].rp=;
tr[rc].lss1=tr[rc].rss1=tr[rc].max1=tr[rc].sum=;
tr[rc].lss0=tr[rc].rss0=tr[rc].max0=tr[rc].r-tr[rc].l+;
}
tr[lc].tag=tr[rc].tag=tr[k].tag;tr[k].tag=-;
// return ;
}
if(tr[k].rev){
tr[k].rev=;tr[lc].rev=;tr[rc].rev=; tr[lc].sum=tr[lc].r-tr[lc].l+-tr[lc].sum; tr[lc].lp^=;tr[lc].rp^=;
swap(tr[lc].max0,tr[lc].max1);
swap(tr[lc].lss0,tr[lc].lss1);
swap(tr[lc].rss0,tr[lc].rss1); tr[rc].sum=tr[rc].r-tr[rc].l+-tr[rc].sum;
tr[rc].lp^=;tr[rc].rp^=;
swap(tr[rc].max0,tr[rc].max1);
swap(tr[rc].lss0,tr[rc].lss1);
swap(tr[rc].rss0,tr[rc].rss1);
}
}
void deal(int k,int v){
if(v){
tr[k].lp=tr[k].rp=;
tr[k].sum=tr[k].max1=tr[k].lss1=tr[k].rss1=tr[k].r-tr[k].l+;
tr[k].max0=tr[k].lss0=tr[k].rss0=;
}
else{
tr[k].lp=tr[k].rp=;
tr[k].max0=tr[k].lss0=tr[k].rss0=tr[k].r-tr[k].l+;
tr[k].sum=tr[k].max1=tr[k].lss1=tr[k].rss1=;
}
}
void vpt(int k){
if(tr[k].l==tr[k].r) return ;
pushdown(k);
vpt(lc);
vpt(rc);
}
void build(int k,int l,int r){
tr[k].l=l;tr[k].r=r;tr[k].tag=-;
if(l==r){
tr[k].lp=tr[k].rp=a[l];
tr[k].sum=tr[k].max1=tr[k].lss1=tr[k].rss1=(a[l]==);
tr[k].max0=tr[k].lss0=tr[k].rss0=(a[l]==);
return ;
}
int mid=l+r>>;
build(lc,l,mid);
build(rc,mid+,r);
updata(k);
}
void cover(int k,int x,int y,int v){
int l=tr[k].l,r=tr[k].r;
if(l==x&&r==y){
vpt(k);
deal(k,v);
if(l!=r) tr[k].tag=v;
return ;
}
pushdown(k);
int mid=l+r>>;
if(y<=mid) cover(lc,x,y,v);
else if(x>mid) cover(rc,x,y,v);
else cover(lc,x,mid,v),cover(rc,mid+,y,v);
updata(k);
}
void rever(int k,int x,int y){
int l=tr[k].l,r=tr[k].r;
if(l==x&&r==y){
vpt(k);
tr[k].sum=tr[k].r-tr[k].l+-tr[k].sum;
tr[k].lp^=;tr[k].rp^=;
swap(tr[k].max0,tr[k].max1);
swap(tr[k].lss0,tr[k].lss1);
swap(tr[k].rss0,tr[k].rss1);
if(l!=r) tr[k].rev=;
return ;
}
pushdown(k);
int mid=l+r>>;
if(y<=mid) rever(lc,x,y);
else if(x>mid) rever(rc,x,y);
else rever(lc,x,mid),rever(rc,mid+,y);
updata(k);
}
int query_sum(int k,int x,int y){
int l=tr[k].l,r=tr[k].r;
if(l==x&&r==y) return tr[k].sum;
pushdown(k);
int mid=l+r>>;
if(y<=mid) return query_sum(lc,x,y);
else if(x>mid) return query_sum(rc,x,y);
else return
query_sum(lc,x,mid)+
query_sum(rc,mid+,y);
}
sgt query_max(int k,int x,int y){
int l=tr[k].l,r=tr[k].r;
if(l==x&&r==y) return tr[k];
pushdown(k);
int mid=l+r>>;
if(y<=mid) return query_max(lc,x,y);
else if(x>mid) return query_max(rc,x,y);
else{
sgt k1=query_max(lc,x,mid);
sgt k2=query_max(rc,mid+,y);
return merge(k1,k2);
}
}
int main(){
freopen("operation.in","r",stdin);
freopen("operation.out","w",stdout);
n=read();m=read();
for(int i=;i<=n;i++) a[i]=read();
build(,,n);
for(int i=,opt,x,y;i<=m;i++){
opt=read();x=read()+;y=read()+;
if(opt<) cover(,x,y,opt);
else if(opt==) rever(,x,y);
else if(opt==) printf("%d\n",query_sum(,x,y));
else{
s=query_max(,x,y);
printf("%d\n",s.max1);
}
}
return ;
}
50分sgtTLE
#include<cstdio>
#include<iostream>
using namespace std;
inline int read(){
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int N=;
int n,m,a[N];
int sum(int l,int r){
int res=;
for(int i=l;i<=r;i++) res+=a[i];
return res;
}
int conti(int l,int r){
int res=;
for(int i=l,j=i;i<=r;){
if(a[i]){
for(j=i+;j<=r;j++){
if(!a[j]) break;
}
res=max(res,j-i);
i=j+;
}
else i++;
}
return res;
}
void out(){
for(int j=;j<n;j++) printf("%d ",a[j]);printf("\n\n\n");
}
int main(){
n=read();m=read();
for(int i=;i<n;i++) a[i]=read();
for(int i=,opt,x,y;i<m;i++){
opt=read();x=read();y=read();
if(opt==){
for(int j=x;j<=y;j++) a[j]=;
}
if(opt==){
for(int j=x;j<=y;j++) a[j]=;
}
if(opt==){
for(int j=x;j<=y;j++) a[j]^=;
}
if(opt==){
printf("%d\n",sum(x,y));
}
if(opt==){
printf("%d\n",conti(x,y));
}
}
return ;
}
90分暴力
/*
本题的难度在于标记的下放。
下面说一下我的做法:
1.覆盖标记:直接打上就好了
2.取反标记:
<1>如果有tag标记,将tag标记取反,退出.
<2>如果有rev标记,直接退出
<3>无标记,打上rev标记,退出
维护:
sum(当前区间和),lss1(区间从左端点连续1的长度),rss1(区间从右端点连续1的长度),sc1(区间连续1的长度)
lss0,rss0,sc0同理。tag(覆盖标记和取反标记整一起了)
*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=1e5+;
const int M=;
int a[N],bl[N],n,m,size;
int tag[M],lss0[M],rss0[M],sc0[M],lss1[M],rss1[M],sc1[M],sum[M];
void init(int i){
tag[i]=-;lss0[i]=rss0[i]=sc0[i]=lss1[i]=rss1[i]=sc1[i]=sum[i]=;
for(int j=(i-)*size+;j<=min(n,i*size);j++)
if(a[j]) sum[i]++;
int fl=,p=;
for(int j=(i-)*size+;j<=min(n,i*size);j++){
if(!a[j]&&!fl) lss0[i]++;
else fl=;
if(!a[j]) p++;else p=;
sc0[i]=max(sc0[i],p);
}
fl=;
for(int j=min(n,i*size);j>(i-)*size;j--){
if(!a[j]&&!fl) rss0[i]++;
else fl=;
}
fl=,p=;
for(int j=(i-)*size+;j<=min(n,i*size);j++){
if(a[j]&&!fl) lss1[i]++;
else fl=;
if(a[j]) p++;else p=;
sc1[i]=max(sc1[i],p);
}
fl=;
for(int j=min(n,i*size);j>(i-)*size;j--){
if(a[j]&&!fl) rss1[i]++;
else fl=;
}
}
void pushdown(int i){
if(tag[i]==-) return;
if(tag[i]==||tag[i]==)
for(int j=(i-)*size+;j<=i*size;j++)
a[j]=tag[i];
else
for(int j=(i-)*size+;j<=i*size;j++)
a[j]^=;
tag[i]=-;
}
void cover(int x,int y,int v){
pushdown(bl[x]);
for(int i=x;i<=min(y,bl[x]*size);i++) a[i]=v;
init(bl[x]);
for(int i=bl[x]+;i<bl[y];i++){
tag[i]=v;
if(v) lss1[i]=rss1[i]=sc1[i]=sum[i]=size,lss0[i]=rss0[i]=sc0[i]=;
else lss1[i]=rss1[i]=sc1[i]=sum[i]=,lss0[i]=rss0[i]=sc0[i]=size;
}
if(bl[x]==bl[y]) return;
pushdown(bl[y]);
for(int i=(bl[y]-)*size+;i<=y;i++) a[i]=v;
init(bl[y]);
}
void rever(int x,int y){
pushdown(bl[x]);
for(int i=x;i<=min(y,bl[x]*size);i++) a[i]^=;
init(bl[x]);
for(int i=bl[x]+;i<bl[y];i++){
if(tag[i]==-) tag[i]=;
else if(tag[i]==) tag[i]=;
else if(tag[i]==) tag[i]=;
else tag[i]=-;
swap(lss0[i],lss1[i]);swap(rss0[i],rss1[i]);
swap(sc0[i],sc1[i]);sum[i]=size-sum[i];
}
if(bl[x]==bl[y]) return;
pushdown(bl[y]);
for(int i=(bl[y]-)*size+;i<=y;i++) a[i]^=;
init(bl[y]);
}
int query_sum(int x,int y){
int ans=;
pushdown(bl[x]);
for(int i=x;i<=min(y,bl[x]*size);i++)
if(a[i]) ans++;
for(int i=bl[x]+;i<bl[y];i++) ans+=sum[i];
if(bl[x]==bl[y]) return ans;
pushdown(bl[y]);
for(int i=(bl[y]-)*size+;i<=y;i++)
if(a[i]) ans++;
return ans;
}
int query_num(int x,int y){
int ans=,l=;
pushdown(bl[x]);
for(int i=x;i<=min(y,bl[x]*size);i++){
if(a[i]) l++;else l=;
ans=max(ans,l);
}
for(int i=bl[x]+;i<bl[y];i++){
l+=lss1[i];
ans=max(ans,l);
ans=max(ans,sc1[i]);
if(lss1[i]!=size) l=rss1[i];
}
if(bl[x]==bl[y]) return max(ans,l);
pushdown(bl[y]);
for(int i=(bl[y]-)*size+;i<=y;i++){
if(a[i]) l++;else l=;
ans=max(ans,l);
}
return ans;
}
int main(){
memset(tag,-,sizeof(tag));
scanf("%d%d",&n,&m);
size=sqrt(n);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
bl[i]=(i-)/size+;
}
for(int i=;i<=bl[n];i++) init(i);
for(int i=,op,x,y;i<=m;i++){
scanf("%d%d%d",&op,&x,&y);x++;y++;
if(op==) cover(x,y,);
if(op==) cover(x,y,);
if(op==) rever(x,y);
if(op==) printf("%d\n",query_sum(x,y));
if(op==) printf("%d\n",query_num(x,y));
}
return ;
}
[SCOI2010]序列操作[分块or线段树]的更多相关文章
- [BZOJ1858] [SCOI2010] 序列操作 解题报告 (线段树)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1858 Description lxhgww最近收到了一个01序列,序列里面包含了n个数, ...
- 【序列操作III】线段树
题目描述 给出序列 a1,a2,…an(0≤ai≤109),有关序列的四种操作: 1. al,al+1,…,ar(1≤l≤r≤n)加上 x(-103≤x≤103) 2. al,al+1,…,ar(1≤ ...
- 【序列操作I】线段树
题目描述 Lxhgww 最近收到了一个 01 序列,序列里面包含了 n(1≤n≤105)个数,这些书要么是 0,要么是 1,现在对这个序列有五种变换操作和询问操作:1. 0 a b ,把[a,b]区间 ...
- 洛谷P4247 序列操作 [清华集训] 线段树
正解:线段树 解题报告: 传送门! 通过这题我get了一个神奇的,叫,线段树五问的东西hhhh 听起来有点中二但感觉真正做题的时候还是比较有用的,,,?感觉会让条理清晰很多呢,所以放一下QwQ →每个 ...
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...
- BZOJ_1858_[Scoi2010]序列操作_线段树
BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...
- BZOJ1858 [Scoi2010]序列操作(线段树)
题目链接 [Scoi2010]序列操作 考验代码能力的一道好题. 思想还是很简单的(直接上线段树),但是比较难写. #include <bits/stdc++.h> using names ...
- bzoj1858[Scoi2010]序列操作 线段树
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 3079 Solved: 1475[Submit][Statu ...
- 【分块】bzoj1858 [Scoi2010]序列操作
分块 Or 线段树 分块的登峰造极之题 每块维护8个值: 包括左端点在内的最长1段: 包括右端点在内的最长1段: 该块内的最长1段: 该块内1的个数: 包括左端点在内的最长0段://这四个是因为可能有 ...
随机推荐
- 解决C# WINFORM程序只允许运行一个实例的几种方法详解
要实现程序的互斥,通常有下面几种方式,下面用 C# 语言来实现: 方法一: 使用线程互斥变量. 通过定义互斥变量来判断是否已运行实例. 把program.cs文件里的Main()函数改为如下代码: u ...
- Spring Boot 概念知识
转 http://rapharino.com/coder/Spring-Boot-Induction/ Spring Boot Induction 发表于 2016-10-29 | 分类于 c ...
- unity, 由Matrix4x4提取Quaternion和Vector3 及 由Quaternion,Vector3构造Matrix4x4
一,由Matrix4x4提取Quaternion和Vector3 Quaternion getRotationFromMatrix(Matrix4x4 m) { return Quat ...
- CUGBACM Codeforces Tranning 3 题解
链接:http://acm.hust.edu.cn/vjudge/contest/view.action? cid=62515#overview 描写叙述:第三场CF训练了.这次做的挺搞笑的,我记得这 ...
- CentOS7 安装 mplayer
我google找到这个方法可以简单快速安装 mplayer 和 vlc,centos 7 only. Please google the latest release for the followin ...
- 聊一聊HTML <pre>标签
聊一聊HTML <pre>标签 我们经常会在要保持文本格式的时候使用pre标签,比如当我们要展示源代码的时候,只要放一个pre标签,然后把源代码直接复制,粘贴,然后在页面上就可以保持好格式 ...
- python学习笔记(7)--爬虫隐藏代理
说明: 1. 好像是这个网站的代理http://www.xicidaili.com/ 2. 第2,3行的模块不用导入,之前的忘删了.. 3. http://www.whatismyip.com.tw/ ...
- Java多线程之Lock的使用<转>
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util ...
- mysql数据库 详解
一.学习目录 1.认识数据库和mysql 2.mysql连接 3.入门语句 4.详解列类型 5.增删改查 INSERT INTO 表名(列1,…… 列n) VALUES(值 1,…… 值 n) ...
- asp.net 正在加载效果实现
最近研究了下asp.net 正在加载的实现原理,总结了以下实现方法 首先,我们有个div显示内容为正在加载.. 当然也可以考虑用图片或者其他的,不过考虑到速度,建议直接文字提示就行,然后设置div ...