14172: 【原4172】rose
题目
题目描述
author: DS TA 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/4172
Description
“玫瑰的红,容易受伤的梦。”
小R同学与小L同学一起去了日本玩耍,她们在一条路上看到了许许多多的红玫瑰,有些玫瑰还在开放,而另一些已经凋谢。好奇的小L想知道某个区间$$[l,r]$$中最多有多少连续的盛开的玫瑰,但调皮的小R要捣乱。她有一种神奇的药水,可以使凋谢的玫瑰立即重新开放,也可以使开放的玫瑰立即枯萎,甚至可以对同一株玫瑰反复使用。小L很生气,找到了你,希望你帮忙应对小R的捣乱。
给出一个01序列和以下三个操作:
$$1\ l\ r\ x$$: 将区间$$[l, r]$$内的所有数变为$$x$$,$$x$$的取值只可能为0或1;
$$2\ l\ r$$: 查询区间$$[l, r]$$内有多少个1;
$$3\ l\ r$$: 查询区间$$[l, r]$$内最长的连续1的数量。
Input Format
输入共m+2行。第一行为2个正整数n和m,n为01序列的长度,m为操作个数;
第二行为n个用空格隔开的数,只可能为0或1;
第三行至第m+2行为m个操作,格式参照问题描述。
Output Format
对于每一个查询操作,输出一行结果。格式见输入输出样例。
Sample Input
8 3
1 1 0 0 1 0 1 0
2 3 5
1 3 7 1
3 2 8
Sample Output
1
6
数据规模与约定
对于100%的数据,$$1\le n, m\le 10^6$$,$$1\le l \le r\le n$$。
Neight99's solution
#include <cmath>
#include <iostream>
using namespace std;
const int maxN = 1e6 + 100;
bool roses[maxN] = {0};
class segmentTree {
private:
struct Node {
int l;
int r;
int lMax;
int rMax;
int mMax;
int amount;
int add;
Node() : l(0), r(0), lMax(0), rMax(0), mMax(0), amount(0), add(0) {}
};
Node *data;
int length;
void buildTree(int X, int l, int r);
void update(int X, int l, int r, bool c);
void pushUp(int X);
void pushDown(int X);
int searchMany(int X, int l, int r);
int searchLongest(int X, int l, int r);
public:
segmentTree(int l = maxN) : length(l) { data = new Node[length * 4 + 100]; }
~segmentTree() { delete[] data; }
void buildTree(int n);
void update(int l, int r, bool c);
int searchMany(int l, int r);
int searchLongest(int l, int r);
};
void segmentTree::pushUp(int X) {
int leftSon = 2 * X, rightSon = 2 * X + 1,
leftLength = data[leftSon].r - data[leftSon].l + 1,
rightLength = data[rightSon].r - data[rightSon].l + 1;
data[X].lMax = data[leftSon].lMax;
data[X].rMax = data[rightSon].rMax;
if (data[X].lMax == leftLength) {
data[X].lMax += data[rightSon].lMax;
}
if (data[X].rMax == rightLength) {
data[X].rMax += data[leftSon].rMax;
}
data[X].amount = data[leftSon].amount + data[rightSon].amount;
data[X].mMax =
max(max(data[leftSon].rMax + data[rightSon].lMax, data[leftSon].mMax),
data[rightSon].mMax);
}
void segmentTree::pushDown(int X) {
int leftSon = 2 * X, rightSon = 2 * X + 1;
if (data[X].add == 0) {
return;
} else if (data[X].l != data[X].r) {
int add = data[X].add;
data[leftSon].add = data[rightSon].add = add;
if (add == 1) {
data[leftSon].lMax = data[leftSon].rMax = data[leftSon].amount =
data[leftSon].mMax = 0;
data[rightSon].lMax = data[rightSon].rMax = data[rightSon].amount =
data[rightSon].mMax = 0;
} else if (add == 2) {
data[leftSon].lMax = data[leftSon].rMax = data[leftSon].amount =
data[leftSon].mMax = data[leftSon].r - data[leftSon].l + 1;
data[rightSon].lMax = data[rightSon].rMax = data[rightSon].amount =
data[rightSon].mMax = data[rightSon].r - data[rightSon].l + 1;
}
data[X].add = 0;
}
}
void segmentTree::buildTree(int n) { buildTree(1, 1, n); }
void segmentTree::buildTree(int X, int l, int r) {
data[X].add = 0;
data[X].l = l;
data[X].r = r;
if (l == r) {
data[X].lMax = roses[l];
data[X].rMax = roses[l];
data[X].mMax = roses[l];
data[X].amount = roses[l];
return;
}
int mid = (l + r) >> 1;
buildTree(2 * X, l, mid);
buildTree(2 * X + 1, mid + 1, r);
pushUp(X);
}
void segmentTree::update(int l, int r, bool c) { update(1, l, r, c); }
void segmentTree::update(int X, int l, int r, bool c) {
if (l <= data[X].l && r >= data[X].r) {
if (c == 0) {
data[X].lMax = data[X].mMax = data[X].rMax = data[X].amount = 0;
} else {
data[X].lMax = data[X].mMax = data[X].rMax = data[X].amount =
data[X].r - data[X].l + 1;
}
data[X].add = c + 1;
} else {
int mid = (data[X].l + data[X].r) >> 1;
pushDown(X);
if (l <= mid) {
update(2 * X, l, r, c);
}
if (r > mid) {
update(2 * X + 1, l, r, c);
}
pushUp(X);
}
}
int segmentTree::searchMany(int l, int r) { return searchMany(1, l, r); }
int segmentTree::searchMany(int X, int l, int r) {
if (data[X].l > r || data[X].r < l) {
return 0;
} else if (l <= data[X].l && data[X].r <= r) {
return data[X].amount;
} else {
int mid = (data[X].l + data[X].r) >> 1;
pushDown(X);
int ans = 0;
return searchMany(2 * X, l, r) + searchMany(2 * X + 1, l, r);
}
}
int segmentTree::searchLongest(int l, int r) { return searchLongest(1, l, r); }
int segmentTree::searchLongest(int X, int l, int r) {
if (data[X].l > r || data[X].r < l) {
return 0;
} else if (data[X].l >= l && data[X].r <= r) {
return data[X].mMax;
} else {
if (data[X].add != 0) {
pushDown(X);
}
int mid = (data[X].l + data[X].r) >> 1;
if (r <= mid) {
return searchLongest(2 * X, l, r);
} else if (l > mid) {
return searchLongest(2 * X + 1, l, r);
} else {
int left1 = searchLongest(2 * X, l, r),
right1 = searchLongest(2 * X + 1, l, r);
int leftRight = data[2 * X].rMax, rightLeft = data[2 * X + 1].lMax;
if (leftRight > mid - l + 1) {
leftRight = mid - l + 1;
}
if (rightLeft > r - mid) {
rightLeft = r - mid;
}
return max(max(left1, right1), (leftRight + rightLeft));
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
segmentTree smt;
for (int i = 1; i < n + 1; i++) {
cin >> roses[i];
}
smt.buildTree(n);
for (int i = 0; i < m; i++) {
int order, l, r, x, ans;
cin >> order;
switch (order) {
case 1:
cin >> l >> r >> x;
smt.update(l, r, x);
break;
case 3:
cin >> l >> r;
ans = smt.searchLongest(l, r);
cout << ans << '\n';
break;
case 2:
cin >> l >> r;
ans = smt.searchMany(l, r);
cout << ans << '\n';
break;
}
}
return 0;
}
WashSwang's solution
#include <iostream>
using namespace std;
const int MAXN=1000001;
int a[MAXN],ans[4*MAXN],tag[4*MAXN],leftc[4*MAXN],rightc[4*MAXN],c[4*MAXN];
inline int ls(int p) {
return p<<1;
}
inline int rs(int p) {
return p<<1|1;
}
inline void push_up(int p,int l,int r) {
int mid=(l+r)>>1;
ans[p]=ans[ls(p)]+ans[rs(p)];
leftc[p]=leftc[ls(p)];
rightc[p]=rightc[rs(p)];
if (mid-l+1==leftc[ls(p)]) leftc[p]+=leftc[rs(p)];
if (r-mid==rightc[rs(p)]) rightc[p]+=rightc[ls(p)];
c[p]=max(max(c[ls(p)],c[rs(p)]),rightc[ls(p)]+leftc[rs(p)]);
}
void build(int l,int r,int p) {
if (l==r)
{
ans[p]=a[l];
leftc[p]=a[l];
rightc[p]=a[l];
c[p]=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,ls(p));
build(mid+1,r,rs(p));
push_up(p,l,r);
}
inline void add_tag(int p,int l,int r,int k)
{
tag[p]=k;
if (k==1)
ans[p]=leftc[p]=rightc[p]=c[p]=0;
if (k==2)
ans[p]=leftc[p]=rightc[p]=c[p]=r-l+1;
}
inline void push_down(int p,int l,int r)
{
int mid=(l+r)>>1;
add_tag(ls(p),l,mid,tag[p]);
add_tag(rs(p),mid+1,r,tag[p]);
tag[p]=0;
}
void update(int nl,int nr,int l,int r,int p,int k)
{
if (nl<=l&&r<=nr)
{
add_tag(p,l,r,k);
return;
}
if (tag[p]!=0) push_down(p,l,r);
int mid=(l+r)>>1;
if (nl<=mid) update(nl,nr,l,mid,ls(p),k);
if (nr>mid) update(nl,nr,mid+1,r,rs(p),k);
push_up(p,l,r);
}
int query(int nl,int nr,int l,int r,int p)
{
if (nl<=l&&r<=nr) return ans[p];
if (tag[p]!=0) push_down(p,l,r);
int mid=(l+r)>>1,sum=0;
if (nl<=mid) sum+=query(nl,nr,l,mid,ls(p));
if (nr>mid) sum+=query(nl,nr,mid+1,r,rs(p));
return sum;
}
int query2(int nl,int nr,int l,int r,int p)
{
if (nl<=l&&r<=nr) return c[p];
int mid=(l+r)>>1,leap=0,lmax=0,rmax=0;
if (tag[p]!=0) push_down(p,l,r);
if (mid>=nl) lmax=query2(nl,nr,l,mid,ls(p));
if (mid<nr) rmax=query2(nl,nr,mid+1,r,rs(p));
leap=min(mid-nl+1,rightc[ls(p)])+min(nr-mid,leftc[rs(p)]);
return max(max(lmax,rmax),leap);
}
int m,n,x,k,l,r;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
build(1,n,1);
for (int i=0;i<m;++i){
scanf("%d%d%d",&k,&l,&r);
if (k==1){
scanf("%d",&x);
update(l,r,1,n,1,x+1);
}
if (k==2)
printf("%d\n",query(l,r,1,n,1));
if (k==3)
printf("%d\n",query2(l,r,1,n,1));
}
return 0;
}