2020.01.03日常总结

17 篇文章 0 订阅
16 篇文章 0 订阅

洛谷P2574

【题意】: AKN觉得第一题太水了,不屑于写第一题,所以他又玩起了新的游戏。在游戏中,他发现,这个游戏的伤害计算有一个规律,规律如下:

( 1 ) (1) (1)拥有一个伤害串为长度为 n n n 01 01 01串。

( 2 ) (2) (2)给定一个范围 [ l , r ] [l,r] [l,r],伤害为伤害串的这个范围内中 1 1 1的个数。

( 3 ) (3) (3)会被随机修改伤害串中的数值,修改的方法是把[l,r]中的所有数 x o r xor xor 1 1 1(即 0 0 0 1 1 1 1 1 1 0 0 0)。

AKN想知道一些时刻的伤害,请你帮助他求出这个伤害。

【思路】: 线段树的题目。

L e n [ l , r ] Len[l,r] Len[l,r]表示区间 ( l , r ) (l,r) (l,r)的长度, S u m [ l , r ] Sum[l,r] Sum[l,r]表示区间 ( l , r ) (l,r) (l,r) 1 1 1的个数。

首先考虑修改操作,我们发现修改操作会让每个数 0 0 0 1 1 1 1 1 1 0 0 0,所以总和(即 1 1 1的个数) S u m [ l , r ] = L e n [ l , r ] − S u m [ l , r ] Sum[l,r]=Len[l,r]-Sum[l,r] Sum[l,r]=Len[l,r]Sum[l,r]

举个例子,比如原来的数串为0001101,其总和为 3 3 3。修改后变为1110010,总和为 7 − 3 = 4 7-3=4 73=4

然后,我们就可以很容易联想到线段树了。

【代码】:

const int N=2e5+100;
int Len[N<<2],sum[N<<2];
bool add[N<<2];int n,m;
inline void pushup(int o){
	sum[o]=sum[o<<1]+sum[o<<1|1];
}//pushup(o):标记上传操作
inline void pushdown(int o){
	sum[o<<1]=Len[o<<1]-sum[o<<1];
	sum[o<<1|1]=Len[o<<1|1]-sum[o<<1|1];
	add[o<<1]^=1;add[o<<1|1]^=1;add[o]=0;
}//pushdown(o):标记下传操作
int a[N],opt,x,y;string s;
void build(int o,int l,int r){
	Len[o]=r-l+1;
	if (l==r){
		sum[o]=a[l];
		add[o]=0;
		return;
	}
	register int mid=(l+r)>>1;
	build(o<<1,l,mid);
	build(o<<1|1,mid+1,r);
	pushup(o);return;
}//建树操作
void updata(int o,int l,int r,int p,int q){
	if (l>q||r<p) return;
	if (p<=l&&r<=q){
		sum[o]=Len[o]-sum[o];
		add[o]^=1;return;
	}
	if (add[o]) pushdown(o);
	register int mid=(l+r)>>1;
	updata(o<<1,l,mid,p,q);
	updata(o<<1|1,mid+1,r,p,q);
	pushup(o);return;
}//修改操作
int query(int o,int l,int r,int p,int q){
	if (l>q||r<p) return 0;
	if (p<=l&&r<=q) return sum[o];
	if (add[o]) pushdown(o);
	register int mid=(l+r)>>1;
	register int answer=0;
	answer+=query(o<<1,l,mid,p,q);
	answer+=query(o<<1|1,mid+1,r,p,q);
	return answer;
}//求和(即求答案)操作
#define gc getchar()
#define g(c) isdigit(c)
inline int read(){
	char c=0;int x=0;bool f=0;
	while (!g(c)) f=c=='-',c=gc;
	while (g(c)) x=x*10+c-48,c=gc;
	return f?-x:x;
}//快读
int main(){
	n=read();m=read();cin>>s;
	for(int i=0;i<n;i++)
		a[i+1]=s[i]-'0';
	build(1,1,n);
	for(int i=1;i<=m;i++){
		opt=read();x=read();y=read();
		if (opt) printf("%d\n",query(1,1,n,x,y));
		else updata(1,1,n,x,y);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值