下午3個半小時的成果
題目描述
Mr.L最近得了妄想症,他對自己生命的歷史和未來產生了一些幻覺。
他的眼前浮現出了自己的生命價值曲線。這條生命線不斷地變化,使他不斷懷疑着自己存在的意義……
Mr.L的生命價值曲線可以被簡化爲一個代表着Mr.L的每個階段的生命價值的序列。其中第i個階段的生命價值爲vi。
當他預感自己成功或失敗時,他的生命線上會遞增或遞減地增加或減少一些價值。他認爲這些價值的變化量是形成等差數列的。
還有時候,他預感到自己的大起大落,此時他一段時間的生命價值會發生反轉。
具體來說,若[l,r]時間內的生命價值發生了反轉,則其中的每個價值都會變成 它原先價值的相反數。
他對自己在某段時間內的生命價值很感興趣,所以還想求出某些時間段內的生命價值總和。
題目思路:
毫無疑問的說,這題明白的話,線段樹的懶標就差不多了。
這個題目要求三種操作:
1. 對區間[l,r]求和
2.對區間[l,r] 加一個 首項爲K 公差爲D 的等差數列
3.對區間[l,r]進行翻轉 a_i=-a_i
首先要解決這個問題的子問題 —— 區間維護等差數列,區間查詢。
考慮 等差數列的兩個屬性 首項a & 公差 d
假設在k節點下,增加了一個首項爲a 公差爲d 的等差數列,向下傳送時 :
相當於在左節點增加一個 首項爲a 公差爲d 的等差數列
相當於在右節點增加一個 首項爲 a+左節點的項數*d 公差爲d 的等差數列
所以維護兩個 類似懶標 的屬性 a & d
另外維護一個答案權值 w.
假設在k節點下 增加首項爲a,公差爲d 的等差數列, 那麼k節點下的權值和 也就對應增加 (2*a+(len-1)*d)*len/2 —— 等差數列求和公式
並且維護的懶標具有可相加性,所以a & d 的傳播 直接向下傳即可。
所以說根據 維護 a&d 就可以維護到每一個節點的權值。
那麼問題來了:
第三種操作,如何實現?
反轉我們可以將其考慮爲 * -1
所以這個題目轉換爲了,有兩種操作 ,第一種操作將[l,r]權值和+w, 第二種操作將[l,r]內權值和 *-1
這就涉及到 區間加法 與 區間乘法 在一起修改時 懶惰標記的優先級
考慮到乘法的優先級比加法的大,所以維護將區間乘法轉區間加法:
假設當前先進行加法: (x+y)*c -> x*c + y*c 也就是說先加後×的話,加法懶惰標記需要成*c。
假設當前先進行乘法:x*c+d 也就是說此時加法標記不需要任何改變
所以 down函數的寫法
void down(int k){
t[k<<1].w=(t[k].mu*t[k<<1].w+t[k].add*(t[k<<1].r-t[k<<1].l+1))%mod;
t[k<<1|1].w=(t[k].mu*t[k<<1|1].w+t[k].add*(t[k<<1|1].r-t[k<<1|1].l+1))%mod;
t[k<<1].add=((t[k<<1].add*t[k].mu)+t[k].add)%mod;
t[k<<1|1].add=((t[k<<1|1].add*t[k].mu)+t[k].add)%mod;
t[k<<1].mu=(t[k<<1].mu*t[k].mu)%mod;
t[k<<1|1].mu=(t[k<<1|1].mu*t[k].mu)%mod;
t[k].mu=1;t[k].add=0;
}
不過這個題,是區間總體加一個數,所以後面不需要×區間長度了
所以這題就轉換爲 區間加法與區間乘法
區間加法加的值 通過 a,d去維護
區間乘法通過乘法懶標去維護
感覺這題...有點麻煩
具體的還是要細細看一下代碼:
Code(你品,你細品):
/*** keep hungry and calm CoolGuang!***/
//#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pp;
const ll INF=1e17;
const int maxn=2e6+6;
const int mod=20020421;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
struct node{
int l,r;
ll w;
ll a,d;
int f;
}t[maxn];
void push(int k){
t[k].w=t[k<<1].w+t[k<<1|1].w;
}
void build(int k,int l,int r){
t[k].l=l;t[k].r=r;
t[k].a=t[k].d=0;
t[k].f=1;
if(l==r){
read(t[k].w);
return ;
}
int mid=(t[k].l+t[k].r)/2;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
push(k);
}
void down(int k){
t[k<<1].a=t[k<<1].a*t[k].f+t[k].a;
t[k<<1|1].a=t[k<<1|1].a*t[k].f+(t[k].a+(t[k<<1|1].l-t[k<<1].l)*t[k].d);
t[k<<1].d=t[k<<1].d*t[k].f+t[k].d;
t[k<<1|1].d=t[k<<1|1].d*t[k].f+t[k].d;
t[k<<1].f*=t[k].f;
t[k<<1|1].f*=t[k].f;
t[k<<1].w=t[k<<1].w*t[k].f+((2*t[k].a+(t[k<<1].r-t[k<<1].l)*t[k].d)*(t[k<<1].r-t[k<<1].l+1))/2;
t[k<<1|1].w=t[k<<1|1].w*t[k].f+((2*(t[k].a+(t[k<<1|1].l-t[k<<1].l)*t[k].d)+(t[k<<1|1].r-t[k<<1|1].l)*t[k].d)*(t[k<<1|1].r-t[k<<1|1].l+1))/2;
t[k].a=t[k].d=0;
t[k].f=1;
}
///ok
void update(int k,int x,int y,ll K,ll D){
if(x<=t[k].l&&y>=t[k].r){
t[k].a+=K+(t[k].l-x)*D;
t[k].d+=D;
t[k].w+=(2*(K+(t[k].l-x)*D)+(t[k].r-t[k].l)*D)*(t[k].r-t[k].l+1)/2;
return;
}
down(k);
int mid=(t[k].l+t[k].r)/2;
if(x<=mid) update(k<<1,x,y,K,D);
if(y>mid) update(k<<1|1,x,y,K,D);
push(k);
}
///ok
void update_f(int k,int x,int y){
if(x<=t[k].l&&y>=t[k].r){
t[k].w*=-1;
t[k].a*=-1;
t[k].d*=-1;
t[k].f*=-1;
return;
}
down(k);
int mid=(t[k].l+t[k].r)/2;
if(x<=mid) update_f(k<<1,x,y);
if(y>mid) update_f(k<<1|1,x,y);
push(k);
}
///ok
ll query(int k,int x,int y){
if(x<=t[k].l&&y>=t[k].r){
return t[k].w;
}
down(k);
int mid=(t[k].l+t[k].r)/2;
ll ans=0;
if(x<=mid) ans+=query(k<<1,x,y);
if(y>mid) ans+=query(k<<1|1,x,y);
push(k);
return ans;
}
int main()
{
read(n);read(m);
build(1,1,n);
for(int i=1;i<=m;i++){
int op,x,y;ll K,D;
scanf("%d%d%d",&op,&x,&y);
if(op==1){
scanf("%lld%lld",&K,&D);
update(1,x,y,K,D);
}
else if(op==2){
printf("%lld\n",query(1,x,y));
}
else
update_f(1,x,y);
}
return 0;
}
/***
w
***/