洛谷 P5358 [SDOI2019]快速查询

题目链接

学习线段树的区间懒标记想法,我们把整个区间当作一个区间。

懒标记有\(add,mul,cov\)

\(add\):区间里每个数加上多少。
\(mul\):区间里每个数乘上多少。
\(cov\):最近一次区间赋值的值是多少。

利用上面三个标记,我们就解决了所有区间修改。

但是单点修改呢?

题目中操作种数只有\(10^5\)种,因此所有单点可以单独提取出来离散化一下。

我们考虑单点赋值,赋值后这个点就符合我们上面的懒标记了,所以我们要把这个值改造一下。

最后单点值\(V_i = (a_i + cov) * mul + add\)

然后就可以了。


#include<bits/stdc++.h>
using namespace std;

const int mod = 1e7 + 19;

int n,Q,t;
struct Que{
    int opt;
    int id; long long val,inv;
}q[100050];

int lsh[100050],ccnt;

long long totsum, totadd, totmul, totinv;
long long cov;
long long temp[100050];

bitset<100050> use;
int U[100050],cnt;

//(temp_i + cov) * totmul + totadd = val_i

long long ksm(long long x,long long y){
    long long z = 1;
    while(y){
        if(y & 1) z = z * x % mod;
        y >>= 1;
        x = x * x % mod;
    }
    return z;
}

long long Ans;

void work(int idx){
    if(q[idx].opt == 1){
    	long long tmp = temp[q[idx].id];
    	tmp += cov; tmp %= mod;
    	tmp *= totmul; tmp %= mod;
    	tmp += totadd; tmp %= mod;
    	tmp = (tmp % mod + mod) % mod;
    	
    	totsum += q[idx].val - tmp; totsum = (totsum % mod + mod) % mod;
    	
    	tmp = q[idx].val;
    	tmp -= totadd; tmp += mod; tmp %= mod;
    	tmp *= totinv; tmp %= mod;
    	tmp -= cov; tmp += mod; tmp %= mod;
    	temp[q[idx].id] = tmp;
    	
    	if(!use[q[idx].id]) { use[q[idx].id] = 1; U[++ cnt] = q[idx].id; }
    }
    if(q[idx].opt == 2){
    	totadd += q[idx].val; totadd %= mod;
    	totsum += 1ll * n * q[idx].val % mod; totsum %= mod;
    }
    if(q[idx].opt == 3){
    	totmul = totmul * q[idx].val % mod; totinv = totinv * q[idx].inv % mod;
    	totadd = totadd * q[idx].val % mod; 
    	totsum = totsum * q[idx].val % mod;
    }
    if(q[idx].opt == 4){
    	totmul = 1; totadd = 0; totinv = 1;
    	cov = q[idx].val; while(cnt) { temp[U[cnt]] = 0; -- cnt; } use.reset();
    	totsum = 1ll * n * q[idx].val % mod;
    }
    if(q[idx].opt == 5){
    	long long tmp = temp[q[idx].id];
    	tmp += cov; tmp %= mod;
    	tmp *= totmul; tmp %= mod;
    	tmp += totadd; tmp %= mod;
    	tmp = (tmp % mod + mod) % mod;
    	Ans += tmp; Ans %= mod;
    	//printf("%lld\n",tmp);
    }
    if(q[idx].opt == 6){
    	totsum = (totsum % mod + mod) % mod;
        Ans += totsum; Ans %= mod;
        //printf("%lld\n",totsum);
    }
}

int main(){
	scanf("%d%d",&n,&Q); n %= mod;
	for(int i = 1; i <= Q; ++ i){
	    scanf("%d",&q[i].opt);
	    if(q[i].opt == 1) scanf("%d%lld",&q[i].id,&q[i].val);
	    else if(q[i].opt <= 4) scanf("%lld",&q[i].val);
	    else if(q[i].opt == 5) scanf("%d",&q[i].id);
	    q[i].val = (q[i].val % mod + mod) % mod;
	    if(q[i].opt == 3) q[i].inv = ksm(q[i].val, mod - 2);
	}
	for(int i = 1; i <= Q; ++ i){
	    if(q[i].opt == 1 || q[i].opt == 5) lsh[++ ccnt] = q[i].id;
	}
	sort(lsh + 1, lsh + ccnt + 1); ccnt = unique(lsh + 1, lsh + ccnt + 1) - lsh - 1;
	for(int i = 1; i <= Q; ++ i){
	    if(q[i].opt == 1 || q[i].opt == 5) q[i].id = lower_bound(lsh + 1, lsh + ccnt + 1, q[i].id) - lsh;
	}
	
	totsum = 0; totmul = 1; totinv = 1; totadd = 0; cov = 0; memset(temp,0,sizeof(temp));
	Ans = 0; use.reset(); cnt = 0;
	
	scanf("%d",&t);
	for(int i = 0; i < t; ++ i){
	    int a,b; scanf("%d%d",&a,&b);
	    long long op = a;
	    for(int j = 1; j <= Q; ++ j){
	        op += b; op %= Q; 
	        work(op + 1);
	    }
	}
	printf("%lld\n",Ans);
	return 0;
}

posted @ 2020-07-27 16:26  zhuzihan  阅读(100)  评论(0编辑  收藏  举报