• 【LOJ#6283】数列分块7


    题目大意:维护一个 N 个数组成的序列,支持区间加、区间乘、单点询问。

    题解:在每一个块中维护两个标记,即:整块加和的标记和整块乘积的标记。不过由于有两个标记,涉及到计算区间总和的顺序问题。
    一个指定块的区间加标记为 (atag),区间乘标记为 (mtag),区间除去标记的和为 (sum)
    第一种方式:((sum+atag)*mtag),第二种方式:(sum*mtag+atag)
    比如:假设现在区间加标记要增加 (val),若采用第一种方式,需要保证 (atag*mtag=add+val),显然这需要使得 (mtag) 的值改变,因此并不合适。
    相反,如果采用第二种方式的话,加法只会改变加法标记,而区间乘法标记改变时,只需将乘法标记同样乘在加法标记上即可,精度符合要求。
    综上,可以理解为乘法标记的优先级更高,即:先做乘法运算,后做加法运算。

    代码如下

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    const int mod=10007;
    
    inline int read(){
    	int x=0,f=1;char ch;
    	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    	return f*x;
    }
    
    int n,q,tot,pos[maxn];
    long long a[maxn];
    struct node{
    	int l,r;
    	long long mul,add;
    }b[1000];
    
    void make_block(){
    	tot=(int)sqrt(n);
    	for(int i=1;i<=tot;i++)b[i].l=(i-1)*tot+1,b[i].r=i*tot;
    	if(b[tot].r<n)++tot,b[tot].l=b[tot-1].r+1,b[tot].r=n;
    	for(int i=1;i<=tot;i++)
    		for(int j=b[i].l;j<=b[i].r;j++)
    			pos[j]=i,b[i].mul=1;
    }
    
    void read_and_parse(){
    	n=read(),q=n;
    	for(int i=1;i<=n;i++)a[i]=read();
    	make_block();
    }
    
    void reset(int x){
    	for(int i=b[x].l;i<=b[x].r;i++)a[i]=(a[i]*b[x].mul+b[x].add)%mod;
    	b[x].add=0,b[x].mul=1;
    }
    
    void modify(int opt,int l,int r,int val){
    	int x=pos[l],y=pos[r];
    	if(x==y){
    		reset(x);
    		for(int i=l;i<=r;i++)opt?a[i]*=val:a[i]+=val,a[i]%=mod;
    	}else{
    		for(int i=x+1;i<=y-1;i++){
    			if(opt==0)b[i].add=(b[i].add+val)%mod;
    			else b[i].add=(b[i].add*val)%mod,b[i].mul=(b[i].mul*val)%mod;
    		}
    		reset(x),reset(y);
    		for(int i=l;i<=b[x].r;i++)opt?a[i]*=val:a[i]+=val,a[i]%=mod;
    		for(int i=b[y].l;i<=r;i++)opt?a[i]*=val:a[i]+=val,a[i]%=mod;
    	}
    }
    
    void solve(){
    	int opt,l,r,val;
    	while(q--){
    		opt=read(),l=read(),r=read(),val=read();
    		if(opt==0)modify(opt,l,r,val);
    		else if(opt==1)modify(opt,l,r,val);
    		else printf("%lld
    ",(a[r]*b[pos[r]].mul+b[pos[r]].add)%mod);
    	}
    }
    
    int main(){
    	read_and_parse();
    	solve();
    	return 0;
    } 
    
  • 相关阅读:
    Flink 多流转换算子
    Flink 基本算子map、keyBy、sum、reduce
    Scala 调用方法时加不加小括号
    Hive rank函数开窗
    Hive 窗口函数
    Scala 集合Map的基本操作
    LOJ#2402. 「THUPC 2017」天天爱射击 / Shooting 整体二分+树状数组
    LOJ#106. 二逼平衡树 树套树
    LOJ#2340. 「WC2018」州区划分
    LOJ#2304. 「NOI2017」泳池(70pts) dp
  • 原文地址:https://www.cnblogs.com/wzj-xhjbk/p/9976554.html
Copyright © 2020-2023  润新知