R - Transformation (线段树&lazy标记)

思路:由于都是对区间进行修改和询问,所以可以用lazy标记该区间是否相等。若不相等总能分成若干个相等小的区间进行求和。具体看代码。

AC代码:

#include<cstdio>
#include<cstring>
using namespace std;
const int N=8e6+5,mod=1e4+7; 
struct node{
	int l,r,lz,s;//这里的a[i].s表示的是这个区间的数等于s 而不是这个区间的总和。 
}a[N];
int n,m,op,x,y,c;
int ksm(int x,int n){ //快速幂板子 
	int ans=1;
	while(n){
		if(n&1) ans=ans*x%mod;
		x=x*x%mod;
		n>>=1;
	}
	return ans;
}
void re(int x){
	if(a[x<<1].lz&&a[x<<1|1].lz&&a[x<<1].s==a[x<<1|1].s)
		a[x].lz=1,a[x].s=a[x<<1].s;
	else a[x].lz=0;
}
void pushdown(int x){
	if(a[x].lz){
		a[x<<1].lz=a[x<<1|1].lz=1;
		a[x<<1].s=a[x<<1|1].s=a[x].s;
		a[x].lz=0;
	}
}
void build(int x,int l,int r){
	a[x].l=l,a[x].r=r,a[x].lz=1,a[x].s=0;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
}
void update(int x,int l,int r,int c){
	if(a[x].lz&&a[x].l>=l&&a[x].r<=r){ //对三个操作的区间修改 
		if(op==1) a[x].s=(a[x].s+c)%mod;
		else if(op==2) a[x].s=(a[x].s*c)%mod;
		else a[x].s=c%mod;
		return;
	}
	pushdown(x);
	int mid=(a[x].l+a[x].r)>>1;
	if(l<=mid) update(x<<1,l,r,c);
	if(r>mid) update(x<<1|1,l,r,c);
	re(x);
} 
int query(int x,int l,int r,int c){
	if(a[x].lz&&a[x].l>=l&&a[x].r<=r) return ksm(a[x].s,c)*(a[x].r-a[x].l+1)%mod;
	else if(a[x].r<l||a[x].l>r) return 0;
	pushdown(x);
	return (query(x<<1,l,r,c)+query(x<<1|1,l,r,c))%mod; 
}
int main(){
	while(~scanf("%d%d",&n,&m)){
		if(!n&&!m) break;
		build(1,1,n);
		while(m--){
			scanf("%d%d%d%d",&op,&x,&y,&c);
			if(op<4) update(1,x,y,c);
			else printf("%d\n",query(1,x,y,c));
		}
	}
	return 0;
}