热身小游戏(线段树,单修区修区查)

热身小游戏(线段树,单修区修区查)

链接:https://ac.nowcoder.com/acm/contest/37160/G
来源:牛客网

Alice 和 Bob 在玩热身小游戏,Alice 给出 Bob 一个整数 n,n 的初始值为 1,然后给出 q 次操作,每次操作格式如下:

1 a 表示将 n 变为 n×a。

2 l r 表示永久撤销第 l 次到第 r 次操作中的 1 操作。

3 输出 n 模 10^9 + 7 的值。

输入描述:
第一行一个正整数 q ( 1≤q≤105) ,表示操作次数。

第二行至第 q + 1,每行一个第一个正整数 op ( 1≤op≤3 ) 表示此次操作的类型。

如果 op 为 1,则后面有一个整数 a (1≤a≤109);
如果 op 为 2,则后面有两个整数 l ,r ( 1≤l≤r≤105 ) ,并且 r小于当前的操作数;
如果 op 为 3,则当前行结束。请对于每个操作执行对应的操作。

操作下标从 1 开始。

输出描述:
每次进行操作 3 时,输出一行一个数代表值。

示例1
输入

6
1 5
3
1 223
3
2 1 4
3

输出
5
1115
1

思路: 将 q 次操作看成一个长度为 q 的序列,初始值都是 1 。对于第 i 次操作,如果是操作 1 则将下标为 i 的位置修改为 n*a,对于操作 2则进行区间修改为 1,对于操作 3 就是区间求乘积。

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lef st,mid,rt<<1
#define rig mid+1,en,rt<<1|1
const int mod=1e9+7,N=5e5+10;
int l,r;
struct pp
{
	int l,r,v,lz;
} p[N];
int ksm(int a,int b)
{
	int ans=1;
	a%=mod;
	while(b)
	{
		if(b%2) ans=ans*a%mod;
		a=a*a%mod;
		b/=2;
	}
	return ans;
}
void pushup(int rt)
{
	p[rt].v=p[rt<<1].v*p[rt<<1|1].v%mod;
}
void build(int st,int en,int rt)
{
	p[rt]= {st,en,1,0};
	if(st==en)
		return;
	int mid=(st+en)>>1;
	build(lef);
	build(rig);
	pushup(rt);

}
void pushdown(int rt)
{
	if(p[rt].lz)
	{
		p[rt<<1].lz=p[rt].lz;
		p[rt<<1|1].lz=p[rt].lz;
		p[rt<<1].v=ksm(p[rt].lz,p[rt<<1].r-p[rt<<1].l+1);
		p[rt<<1|1].v=ksm(p[rt].lz,p[rt<<1|1].r-p[rt<<1|1].l+1);
		p[rt].lz=0;
	}
}
void modify(int rt,int val)
{
	if(p[rt].l>=l&&p[rt].r<=r)
	{
		p[rt].lz=val;
		p[rt].v=ksm(val,p[rt].r-p[rt].l+1);
	}
	else
	{
		pushdown(rt);
		int mid=(p[rt].l+p[rt].r)>>1;
		if(l<=mid)
			modify(rt<<1,val);
		if(r>mid)
			modify(rt<<1|1,val);
		pushup(rt);
	}
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(nullptr);
	int n,q,i,j,k;
	cin>>q;
	build(1,q,1);
	for(i=1; i<=q; i++)
	{
		int op,x;
		cin>>op;
		if(op==3)
			cout<<p[1].v%mod<<"\n";
		else if(op==2)
		{
			cin>>l>>r;
			modify(1,1);
		}
		else
		{
			cin>>x;
			l=r=i;
			modify(1,x);
		}
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值