1 条题解

  • 0
    @ 2025-8-24 22:06:08

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar DDOSvoid
    **

    搬运于2025-08-24 22:06:08,当前版本为作者最后更新于2018-11-05 18:58:15,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    好像没人 A 掉啊

    果然毒瘤题,虽然不卡分块

    另外写 solution 的人的语文烂的要死

    updeta: 为什么这么多人直接交题解啊?

    std 已经更改过,直接提交不能 AC 请自重(当然不影响阅读

    Solution

    测试点 1

    逐秒模拟即可

    测试点 2 ~ 6

    暴力模拟,每个位置多记时间这个标记,复杂度 O(nm)O(nm)

    测试点 7 ~ 9

    其实第 7 个点,暴力也能过

    假设一个点的值为 v,考虑单点修改 a,看下面这个图(忽略了 ×b\times b

    1

    也就是说,如果在时间 ttaa 增加 vv,我们只需要 sum=vbtsum-=v*b*t 即可,最终在时间 t1t_1 查询时我们直接查询 sum+abt1sum+a*b*t_1,所以可用线段树维护区间和以及区间 aba*b 的和,修改就是单点修改,查询就是区间查询

    测试点 10 ~ 11

    观察 aa 的单点修改,修改的时候 bbtt 是常量,如果能维护 b 的区间和,那么是可以修改区间的,所以线段树 + 标记 即可

    测试点 12 ~ 13

    bb 仅有单点修改,所以上一种是一样的,再加一个对 b 的单点修改即可

    测试点 14

    仅有询问,所以直接线段树维护区间和以及区间 aba*b 的和即可

    这个点好像没啥意义

    测试点 15 ~ 17

    仅仅是增加了 b 的区间修改,至此,我们的想法已经非常明确

    即我们要维护 a\sum av\sum vb\sum bab\sum a*b,那么要维护这些值,我们需要一些标记

    对于线段树处理多标记,有一个统一的规则,即对于线段树上的任意一个点,我们在递归到它的时候(即它的父亲的 tag 全部下放),它要维护的值一定是正确的。

    所以接下来我们考虑的更新标记都是要传给子节点的标记

    注意到 v\sum v 一定是形如 vxayb+z\sum v - x*\sum a - y*\sum b+z 这种形式,下面我们根据操作还确定标记

    考虑区间改 a 的操作,我们需要一个 addaadda 标记,表示 v\sum v 还要减多少倍的 b\sum b,还有一个标记 AddaAdda,表示 a 增加了多少,在改 a 的时候 (a+=va+=v),adda+=vtadda+=v*tAdda+=vAdda+=v,如果之前对这个点有过区间改 b 的话,最后我们只是拿 addabadda*\sum b,而 b\sum b 是未更新的 b\sum b,所以还要记一个标记 addvaddv 表示 v\sum v 要加上多少常量,addv=Addbvtaddv-=Addb*v*t

    区间改 b 的操作类似

    区间改 v ...

    现在考虑具体的标记下传到值

    仅考虑左儿子的情况,形如 addaadda' 为父亲的标记

    v=vaddbaaddab+addv(ml+1)\sum v = \sum v-addb'*a-adda'*b+addv'*(m-l+1)

    $\sum ab=\sum ab+Adda'*Addb'*(m-l+1)+Adda'*\sum b+Addb'*\sum a$

    a=a+Adda(ml+1)\sum a =\sum a + Adda'*(m-l+1)

    b=b+Addb(ml+1)\sum b=\sum b + Addb'*(m-l+1)

    注意更新顺序,下面考虑标记下传到标记

    addv=addvaddbAddaaddaAddb+addvaddv=addv-addb'*Adda-adda'*Addb+addv'

    adda=adda+addaadda=adda+adda'

    addb=addb+addbaddb=addb+addb'

    Adda=Adda+AddaAdda=Adda+Adda'

    Addb=Addb+AddbAddb=Addb+Addb'

    同样注意更新顺序

    附上丑陋的 std

    #include<iostream>
    #include<cstdio>
    #include<cctype>
    #define maxn 500010
    #define ll long long
    #define gc getchar
    using namespace std;
    
    int n, m, a[maxn], b[maxn], v[maxn];
    
    const int p = 1000000007;
    
    int read(){
    	int x = 0, f = 0; char c = gc();
    	while(!isdigit(c)){if(c == '-') f = 1; c = gc();}
    	while(isdigit(c)){x = x * 10 + c - '0'; c = gc();}
    	return f ? -x : x;
    }
    
    #define lc i << 1
    #define rc i << 1 | 1
    struct seg{	
    	ll v, a, b, adda, addb, addv, mul, Adda, Addb, Addmul;
    }T[maxn * 4]; 
    inline void maintain(int i){
    	T[i].v = (T[lc].v + T[rc].v) % p;
    	T[i].mul = (T[lc].mul + T[rc].mul) % p;
    	T[i].a = (T[lc].a + T[rc].a) % p;
    	T[i].b = (T[lc].b + T[rc].b) % p;
    }	
    
    void build(int i, int l, int r){
    	if(l == r){
    		T[i].v = v[l]; T[i].a = a[l]; 
    		T[i].b = b[l]; T[i].mul = 1ll * a[l] * b[l] % p; return ;
    	} int m = l + r >> 1;
    	build(lc, l, m); build(rc, m + 1, r);
    	maintain(i);
    }
    
    void pushdown(int i, int l, int r){
    	ll &adda = T[i].adda, &addb = T[i].addb, &addv = T[i].addv; int m = l + r >> 1;
    	ll &Adda = T[i].Adda, &Addb = T[i].Addb, &Addmul = T[i].Addmul;
    	
    	T[lc].v = (T[lc].v - adda * T[lc].b - addb * T[lc].a + addv * (m - l + 1)) % p;
    	T[rc].v = (T[rc].v - adda * T[rc].b - addb * T[rc].a + addv * (r - m)) % p;
    	T[lc].mul = (T[lc].mul + Adda * Addb % p * (m - l + 1) % p + Adda * T[lc].b + Addb * T[lc].a) % p;
    	T[rc].mul = (T[rc].mul + Adda * Addb % p * (r - m) % p  + Adda * T[rc].b + Addb * T[rc].a) % p;
    	T[lc].a = (T[lc].a + Adda * (m - l + 1)) % p; T[rc].a = (T[rc].a + Adda * (r - m)) % p;
    	T[lc].b = (T[lc].b + Addb * (m - l + 1)) % p; T[rc].b = (T[rc].b + Addb * (r - m)) % p;
    	
    	T[lc].addv = (T[lc].addv + addv - T[lc].Adda * addb - T[lc].Addb * adda) % p;
    	T[rc].addv = (T[rc].addv + addv - T[rc].Adda * addb - T[rc].Addb * adda) % p;
    	
    	T[lc].adda = (T[lc].adda + adda) % p;
    	T[rc].adda = (T[rc].adda + adda) % p;
    	
    	T[lc].addb = (T[lc].addb + addb) % p;
    	T[rc].addb = (T[rc].addb + addb) % p;
    	
    	T[lc].Adda = (T[lc].Adda + Adda) % p;
    	T[rc].Adda = (T[rc].Adda + Adda) % p;
    	
    	T[lc].Addb = (T[lc].Addb + Addb) % p;
    	T[rc].Addb = (T[rc].Addb + Addb) % p;
    	
    	//T[lc].Addmul = (T[lc].Addmul + Addmul) % p;
    	//T[rc].Addmul = (T[rc].Addmul + Addmul) % p;
    	
    	adda = addb = addv = Adda = Addb = Addmul = 0;
    }	
    
    void update_adda(int i, int l, int r, int L, int R, ll v, ll t){
    	if(l > R || r < L) return ;
    	if(L <= l && r <= R){
    		T[i].v = (T[i].v - T[i].b * v % p * t) % p;
    		T[i].a = (T[i].a + 1ll * v * (r - l + 1)) % p; T[i].mul = (T[i].mul + T[i].b * v) % p;
    		T[i].adda = (T[i].adda + 1ll * v * t) % p; 
    		T[i].addv = (T[i].addv - T[i].Addb * v % p * t) % p;
    		T[i].Adda = (T[i].Adda + v) % p; //T[i].Addmul = (T[i].Addmul + v * T[i].Addb) % p;
    		return ;
    	} int m = l + r >> 1; pushdown(i, l, r);
    	update_adda(lc, l, m, L, R, v, t); update_adda(rc, m + 1, r, L, R, v, t);
    	maintain(i);
    }
    
    void update_addb(int i, int l, int r, int L, int R, ll v, ll t){
    	if(l > R || r < L) return ;
    	if(L <= l && r <= R){
    		T[i].v = (T[i].v - T[i].a * v % p * t) % p;
    		T[i].b = (T[i].b + 1ll * v * (r - l + 1)) % p; T[i].mul = (T[i].mul + T[i].a * v) % p;
    		T[i].addb = (T[i].addb + 1ll * v * t) % p;
    		T[i].addv = (T[i].addv - T[i].Adda * v % p * t) % p;
    		T[i].Addb = (T[i].Addb + v) % p; //T[i].Addmul = (T[i].Addmul + v * T[i].Adda) % p;
    		return ;
    	} int m = l + r >> 1; pushdown(i, l, r);
    	update_addb(lc, l, m, L, R, v, t); update_addb(rc, m + 1, r, L, R, v, t);
    	maintain(i);
    }
    
    void update_addv(int i, int l, int r, int L, int R, int v){
    	if(l > R || r < L) return ;
    	if(L <= l && r <= R){
    		T[i].v = (T[i].v + 1ll * v * (r - l + 1)) % p;
    		T[i].addv = (T[i].addv + v) % p;
    		return ;
    	} int m = l + r >> 1; pushdown(i, l, r);
    	update_addv(lc, l, m, L, R, v); update_addv(rc, m + 1, r, L, R, v);
    	maintain(i);
    }
    
    ll query(int i, int l, int r, int L, int R, int t){
    	if(l > R || r < L) return 0;
    	if(L <= l && r <= R) return (T[i].v + T[i].mul * t) % p;
    	int m = l + r >> 1; pushdown(i, l, r);
    	return (query(lc, l, m, L, R, t) + query(rc, m + 1, r, L, R, t)) % p;
    }
    
    inline void solve_1(){
    	int t = read(), x = read(), y = read();
    	ll v = query(1, 1, n, x, y, t); v = (v % p + p) % p;
    	printf("%lld\n", v);
    }
    
    inline void solve_2(){
    	int t = read(), x = read(), y = read(), z = read();
    	update_adda(1, 1, n, x, y, z, t);	
    }
    
    inline void solve_3(){
    	int t = read(), x = read(), y = read(), z = read();
    	update_addb(1, 1, n, x, y, z, t);	
    }
    
    inline void solve_4(){
    	int t = read(), x = read(), y = read(), z = read();
    	update_addv(1, 1, n, x, y, z);	
    }
    
    int main(){
    	n = read(); m = read();
    	for(int i = 1; i <= n; ++i) v[i] = read(), a[i] = read(), b[i] = read();
    	build(1, 1, n);
    	for(int i = 1; i <= m; ++i){
    		int opt; opt = read();
    		switch(opt){
    			case 1 : solve_1(); 
    			case 2 : solve_2(); 
    			case 3 : solve_3(); 
    			case 4 : solve_4(); 
    		}
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    4003
    时间
    2500ms
    内存
    500MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者