Fork me on GitHub

F. Flip (2021 ICPC Asia Taiwan)

https://codeforces.com/gym/103373/problem/F

namo,第一篇这里的博客来记录下我的愚蠢吧qaq

本题题意:

给定由0、1组成的数组a,要求支持两种操作,opt1:对于i∈[l,r],a[i] = 1 - a[i]; opt2:查询区间”美丽“序列的pair对数。(定义一个序列美丽为:如果当前序列是1 0 1 0 1 0 1 0 …… 的某个子串,即该序列是美丽的;eg : [1]、[0]、[1,0,1]都是美丽的序列,而[1,1]、[1,0,0]则不是美丽序列)

思路:

"当你想不到线段树该维护什么的时候,不妨就先设想直接维护答案,再看看答案由什么可以得来的思路来解决问题"---P500
namo,操作一加个区间反转的tag即可解决,操作二的话我们可以设想直接维护答案ans,那现在就是考虑pushup操作如何利用左儿子区间和右儿子区间的信息维护当前结点区间的信息,容易发现当左儿子的右端点 == 右儿子的左端点时,root.ans = lson.ans + rson.ans; else的话,则会产生额外的贡献,首先一个连续01串会产生的贡献是 len * (len+1) / 2,合并后产生的新贡献即为: (l+r) * (l+r+1) / 2 - l * (l+1) / 2 - r * (r+1) / 2 ,简单计算可知增加的贡献恰好等于 l*r,l和r分别是区间从左开始以及从右开始最长的01交替序列长度,另外还需要维护区间最左边和最右边分别是0还是1,所以线段树需要多维护这两个信息,下面附上代码。

点击查看代码
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,abm,mmx,avx,avx2,popcnt,tune=native")
#pragma GCC target ("avx2,fma")
#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")
#include<bits/stdc++.h>
#include <ext/rope>
using namespace __gnu_cxx;
#define int long long
#define endl '\n'
using namespace std;
int IOS = []() {ios::sync_with_stdio(0); std::cin.tie(nullptr); std::cout.tie(nullptr); return 0; }();
const int N = 2e5+10;
int a[N];
struct node{
	int l,r;
	bool tag;
	bool lv,rv; //最左、右的值 
	int ans;   
	int lenl,lenr; // 交替序列长度 
}tr[N*4];
node pushup(node &ro,node &L,node &R)
{
	ro.l = L.l;   ro.r = R.r;
	ro.lv = L.lv; ro.rv = R.rv;
	ro.tag = 0;
	if(L.rv==R.lv)
	{
		ro.lenl = L.lenl; 
		ro.lenr = R.lenr;
		ro.ans = L.ans + R.ans;
		return ro;
	}
	ro.lenl = (L.lenl == L.r-L.l+1) ? L.lenl + R.lenl : L.lenl;
	ro.lenr = (R.lenr == R.r-R.l+1) ? R.lenr + L.lenr : R.lenr;
	ro.ans = L.ans + R.ans + L.lenr * R.lenl;
	return ro;
}
void pushup(int u)
{
	pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void pushdown(int u)
{
	if(tr[u].tag)
	{
		tr[u<<1].lv ^= 1;  tr[u<<1].rv ^= 1;
		tr[u<<1|1].lv ^= 1;  tr[u<<1|1].rv ^= 1; 
		tr[u<<1].tag ^= 1; tr[u<<1|1].tag ^= 1;
		tr[u].tag = 0;
	}
}
void build(int u,int l,int r)
{
	tr[u] = {l,r};
	if(l==r)
	{
		tr[u].lv = tr[u].rv = a[l];
		tr[u].ans = tr[u].lenl = tr[u].lenr = 1;
		return;
	}
	int mid = l + r >>1;
	build(u<<1,l,mid); build(u<<1|1,mid+1,r);
	pushup(u);
}
void update(int u,int l,int r)
{
	if(tr[u].l>=l&&tr[u].r<=r)
	{
		tr[u].lv ^= 1; tr[u].rv ^= 1; tr[u].tag ^= 1;
		return;
	}
	int mid = tr[u].l + tr[u].r >>1;
	pushdown(u);
	if(l<=mid) update(u<<1,l,r);
	if(r>mid)  update(u<<1|1,l,r);
	pushup(u);
}
node query(int u,int l,int r)
{
	if(tr[u].l>=l&&tr[u].r<=r) return tr[u];
	int mid = tr[u].l + tr[u].r >>1;
	pushdown(u);
	if(r<=mid)  return query(u<<1,l,r);
	else if(l>mid) return query(u<<1|1,l,r);
	else 
	{
		node ro,L = query(u<<1,l,r),R = query(u<<1|1,l,r);
		pushup(ro,L,R);
		return ro;
	}
}
void solve()
{
	int n,q; cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>a[i];
	build(1,1,n);
	while(q--)
	{
		int opt,l,r; cin>>opt>>l>>r;
		if(opt==1) update(1,l,r);
		else cout<<query(1,l,r).ans<<endl;
	}
} 
signed main()
{
	int tt = 1;
	while(tt--)
	{
		solve();
	}
}
posted @ 2021-11-04 20:30  LeiLeiKunLe  阅读(208)  评论(0)    收藏  举报