题意:
就是给你一个01数组,然后给你m次操作,每次要么是让[l,r]这段区间的0和1都翻转,要么是查询[l,r]这段区间有多少好的子区间。好的区间定义为,这个区间的0和1是间隔的,也就是没有连续>=2个的0或者1。
思考:
- 当时思考来思考去,就感觉不太好操作,因为感觉线段树不知道咋维护答案,害,还是对线段树的区间合并理解的不透彻。
- 其实就正常的去维护,只要到L>=l&&R<=r的时候,线段树里的东西就要修改,然后如果是区间合并的话,在pushup的时候,这个节点就由两个儿子来合并出来就可以了。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e18;
const int N = 2e5+10,M = 2010;
int T,n,m,k;
int va[N];
struct seg_tree{
#define node_l node<<1
#define node_r node<<1|1
struct Node{
int L,R,sum,laz;
int lop,rop;
int lsum,rsum;
}t[4*N];
void pushdown(int node)
{
if(!t[node].laz) return ;
t[node_l].laz ^= 1;
t[node_l].lop ^= 1;t[node_l].rop ^= 1;
t[node_r].laz ^= 1;
t[node_r].lop ^= 1;t[node_r].rop ^= 1;
t[node].laz = 0;
}
void pushup(int node) //当前node由两个儿子合并
{
t[node].lop = t[node_l].lop;
t[node].rop = t[node_r].rop;
t[node].sum = t[node_l].sum+t[node_r].sum;
t[node].lsum = t[node_l].lsum;
t[node].rsum = t[node_r].rsum;
if(t[node_l].rop!=t[node_r].lop)
{
t[node].sum += t[node_l].rsum*t[node_r].lsum;
if(t[node_l].lsum==t[node_l].R-t[node_l].L+1)
t[node].lsum += t[node_r].lsum;
if(t[node_r].rsum==t[node_r].R-t[node_r].L+1)
t[node].rsum += t[node_l].rsum;
}
}
void build(int node,int l,int r)
{
t[node].L = l,t[node].R = r;
if(l==r)
{
t[node].sum = 1;
t[node].lop = t[node].rop = va[l];
t[node].lsum = t[node].rsum = 1;
return ;
}
int mid = (l+r)>>1;
build(node_l,l,mid);build(node_r,mid+1,r);
pushup(node);
}
void update(int node,int l,int r)
{
if(t[node].L>=l&&t[node].R<=r) //需要修改的就这些,其他的都是不变的。
{
t[node].laz ^= 1;
t[node].lop ^= 1;t[node].rop ^= 1;
return ;
}
pushdown(node);
int mid = (t[node].L+t[node].R)>>1;
if(r<=mid) update(node_l,l,r);
else if(l>mid) update(node_r,l,r);
else update(node_l,l,mid),update(node_r,mid+1,r);
pushup(node);
}
Node query(int node,int l,int r)
{
if(t[node].L>=l&&t[node].R<=r) return t[node];
pushdown(node);
int mid = (t[node].L+t[node].R)>>1;
if(r<=mid) return query(node_l,l,r);
else if(l>mid) return query(node_r,l,r);
else //查询答案的时候注意,如果分成了两个区间需要把两个区间合并起来,再返回。
{
Node now;
Node tl = query(node_l,l,mid);
Node tr = query(node_r,mid+1,r);
now.L = tl.L,now.R = tr.R;
now.lop = tl.lop,now.rop = tr.rop;
now.sum = tl.sum+tr.sum;
now.lsum = tl.lsum,now.rsum = tr.rsum;
if(tl.rop!=tr.lop)
{
now.sum += tl.rsum*tr.lsum;
if(tl.lsum==tl.R-tl.L+1) now.lsum += tr.lsum;
if(tr.rsum==tr.R-tr.L+1) now.rsum += tl.rsum;
}
return now;
}
pushup(node);
}
}tsum;
signed main()
{
IOS;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>va[i];
tsum.build(1,1,n);
while(m--)
{
int op,a,b;
cin>>op>>a>>b;
if(op==1) tsum.update(1,a,b);
else cout<<tsum.query(1,a,b).sum<<"\n";
}
return 0;
}
题意:
就是给你一个数组,然后又m次操作,每次操作要么是让第x个数变成y,要么是查询[l,r]区间最大值是几,并且有多少个。
思考:
- 这个也是经典的区间合并,修改的时候,如果跨区间了也要pushup,当前节点的答案由两个儿子处理出来。然后查询的时候也是,如果跨区间了,那么就要把两个区间的答案合并起来。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e18;
const int N = 2e5+10,M = 2010;
int T,n,m,k;
int va[N];
struct set_tree{
#define node_l node<<1
#define node_r node<<1|1
struct node
{
int L,R;
int maxn;
int sum;
}t[4*N];
void build(int node,int l,int r)
{
t[node].L = l,t[node].R = r;
if(l==r)
{
t[node].maxn = va[l];
t[node].sum = 1;
return ;
}
int mid = l+r>>1;
build(node_l,l,mid);
build(node_r,mid+1,r);
t[node].maxn = max(t[node_l].maxn,t[node_r].maxn);
if(t[node_l].maxn == t[node].maxn) t[node].sum += t[node_l].sum;
if(t[node_r].maxn == t[node].maxn) t[node].sum += t[node_r].sum;
}
void change(int node,int x,int value)
{
if(t[node].L>x||t[node].R<x) return ;
if(t[node].L==x&&t[node].R==x)
{
t[node].maxn = value;
t[node].sum = 1;
return ;
}
change(node_l,x,value);
change(node_r,x,value);
t[node].maxn = max(t[node_l].maxn,t[node_r].maxn);
t[node].sum = 0;
if(t[node_l].maxn == t[node].maxn) t[node].sum += t[node_l].sum;
if(t[node_r].maxn == t[node].maxn) t[node].sum += t[node_r].sum;
}
PII query(int node,int l,int r)
{
if(t[node].L>=l&&t[node].R<=r)
{
return {t[node].maxn,t[node].sum};
}
int mid = (t[node].L+t[node].R)>>1;
if(r<=mid) return query(node_l,l,r);
else if(l>mid) return query(node_r,l,r);
else
{
auto t1 = query(node_l,l,r),t2 = query(node_r,l,r);
if(t1.fi==t2.fi) return {t1.fi,t1.se+t2.se};
else if(t1.fi>t2.fi) return t1;
else return t2;
}
}
}tsum;
signed main()
{
IOS;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>va[i];
tsum.build(1,1,n);
for(int i=1;i<=m;i++)
{
string op;
int a,b;
cin>>op>>a>>b;
if(op=="Ask")
{
auto now = tsum.query(1,a,b);
cout<<now.fi<<" "<<now.se<<"\n";
}
else tsum.change(1,a,b);
}
return 0;
}