题目链接如下:
目录
方法一
参考HDU4578 线段树多种操作的实现_4578.se_tzteyang的博客-优快云博客
很自然的想法就是对加,乘,求幂的和,以及设置值分别维护懒标记,但是这样的缺点在于,每次push_down的时候需要更新很多东西,也导致了超时。
方法二
参考HDU4578-Transformation (线段树多种区间操作)_小冬囍的博客-优快云博客
这里的做法是只维护一个区间内一样值的节点,那么加,乘,设置值都只需要统一操作即可。在求幂的和的时候也只需要区间统一求取。
代码如下所示:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<cmath>
#include<climits>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
const int MAXN=1e5+10;
const int MOD=10007;
bool flag[MAXN<<2];
ll x[MAXN<<2];
void push_up(int rt){
if (!flag[rt<<1]||!flag[rt<<1|1]) {
flag[rt]=false;
} else if (x[rt<<1]!=x[rt<<1|1]){
flag[rt]=false;
} else {
flag[rt]=true;
x[rt]=x[rt<<1];
}
}
void push_down(int rt){
if (flag[rt]){
flag[rt<<1]=flag[rt<<1|1]=true;
x[rt<<1]=x[rt<<1|1]=x[rt];
flag[rt]=false;
}
}
void update(int ul,int ur,int op,int c,int l,int r,int rt){
// cout<<"["<<l<<","<<r<<"]"<<endl;
if (ul<=l && r<=ur && flag[rt]){
if (op==1){
x[rt]=(x[rt]+c)%MOD;
} else if (op==2){
x[rt]=x[rt]*c%MOD;
} else {
x[rt]=c;
}
return;
}
push_down(rt);
int mid=(l+r)>>1;
if (ul <= mid) {
update(ul,ur,op,c,lson);
}
if (ur > mid) {
update(ul,ur,op,c,rson);
}
push_up(rt);
}
ll query(int ul,int ur,int q,int l,int r,int rt){
if (ul<=l && r<=ur && flag[rt]){
ll sum=1;
for (int i = 0; i < q; ++i) {
sum=sum%MOD*x[rt]%MOD;
}
sum=sum*(r-l+1)%MOD;
return sum;
}
push_down(rt);
ll ans=0;
int mid=(l+r)>>1;
if (ul<=mid){
ans=(ans+query(ul,ur,q,lson))%MOD;
}
if (ur>mid){
ans=(ans+query(ul,ur,q,rson))%MOD;
}
return ans;
}
int main(){
int n,m,op,l,r,c;
while (~scanf("%d %d",&n,&m)){
if (n==0 && m==0) break;
memset(x,0, sizeof(x));
memset(flag,1, sizeof(flag));
while (m--){
scanf("%d %d %d %d",&op,&l,&r,&c);
// cout<<"m:"<<m<<endl;
// cout<<op<<","<<l<<","<<r<<","<<c<<endl;
if (op==4){
printf("%d\n", query(l,r,c,1,n,1));
} else{
update(l,r,op,c,1,n,1);
}
}
}
return 0;
}