又是一个坑,之前的文章里也说过是因为不知道为什么会得到个样例从而弃坑的,现在看来原来是不知道分数取模,真的有点惨,除去这点之后这道题的思路基本和我当时想的一模一样,维护一个能够查询区间和区间平方和的线段树,然后进行一些小计算即可,鉴于我比较懒,所以直接从网上抄了一个自认为不错的,然后复刻封装了一下,之后又犯了一些低级错误debug了一阵,从而解决了这个问题。
简单说说题目,求每次攻击后的流量期望并不断做区间加法,期望流量考虑单点,假如永远会引流,那么期望就是(C + 1) / 2然而很多时候系统可以自己解决,而这些流量的离散和正好是1加到x - 1即x(x - 1)那么把这个除C就是减小的部分了,所以这道题基本就解决了,算出区间和和区间平方和,然后常数乘r - l + 1就是区间的结果了。
贴代码
# include <cstdio>
# include <algorithm>
using namespace std;
namespace tree
{
# define ini int mid = (l + r) >> 1, kl = k << 1 | 1, kr = (k << 1) + 2
const int Mod = 1e9 + 7;
const int MAX_N = 3e5;
typedef long long ll;
ll A[MAX_N / 3];
//ll maxx[MAX_N], minn[MAX_N];
ll val[MAX_N], v2[MAX_N];
ll x[MAX_N];
inline void check(ll &a)
{
a >= Mod ? a = a - Mod : a;
}
void up(int k , int l , int r)
{
ini;
val[k] = val[kl] + val[kr];
v2[k] = v2[kl] + v2[kr];
check(val[k]);
check(v2[k]);
//maxx[k] = max(maxx[kl] , maxx[kr]);
//minn[k] = min(minn[kl] , minn[kr]);
}
void down(int k , int l , int r)
{
if(r - l == 1)
return;
ini;
if(x[k])
{
x[kl] += x[k];
x[kr] += x[k];
v2[kl] += ((mid - l) * x[k] % Mod * x[k] % Mod + 2 * val[kl] * x[k] % Mod) % Mod;
v2[kr] += ((r - mid) * x[k] % Mod * x[k] % Mod + 2 * val[kr] * x[k] % Mod) % Mod;
val[kl] += (mid - l) * x[k] % Mod;
val[kr] += (r - mid) * x[k] % Mod;
check(x[kl]);
check(x[kr]);
check(v2[kl]);
check(v2[kr]);
check(val[kl]);
check(val[kr]);
//maxx[kl] += x[k];
//maxx[kr] += x[k];
//minn[kl] += x[k];
//minn[kr] += x[k];
}
x[k] = 0;
}
void cons(int k , int l , int r)
{
if(r - l == 1)
{
x[k] = 0;
val[k] = A[l];
v2[k] = A[l] * A[l] % Mod;
return;
}
ini;
cons(kl , l , mid);
cons(kr , mid , r);
up(k , l , r);
}
void add(int k , int l , int r , int a , int b , int v)
{
if(a <= l && r <= b)
{
v2[k] += ((ll)(r - l) * v % Mod * v % Mod + 2 * v * val[k] % Mod) % Mod;
val[k] += (ll)(r - l) * v % Mod;
//maxx[k] += v;
// minn[k] += v;
x[k] += v;
check(v2[k]);
check(val[k]);
check(x[k]);
return;
}
down(k , l , r);
ini;
if(a < mid)
add(kl , l , mid , a , b , v);
if(mid < b)
add(kr , mid , r , a , b , v);
up(k , l , r);
}
void ques(int k , int l , int r , int a , int b , ll &q1 , ll &q2)
{
if(a <= l && r <= b)
{
q1 += val[k];
q2 += v2[k];
check(q1);
check(q2);
return;
}
ini;
down(k , l , r);
if(a < mid)
ques(kl , l , mid , a , b , q1 , q2);
if(mid < b)
ques(kr , mid , r , a , b , q1 , q2);
up(k , l , r);
}
}
using tree::check;
using tree::cons;
using tree::add;
using tree::ques;
using tree::A;//??
using tree::ll;
using tree::Mod;
ll po(ll a , ll b , ll mo)
{
ll ans = 1;
while(b)
{
if(b & 1)
ans = ans * a % mo;
b >>= 1;
a = a * a % mo;
}
return ans;
}
inline ll ni(ll a)
{
return po(a , Mod - 2 , Mod);
}
int N, C, Q;
int nC, n2;
int main()
{
scanf("%d %d %d", &N, &C, &Q);
nC = ni(C);
n2 = ni(2);
int i;
for(i = 0 ; i < N ; i++)
scanf("%d", &A[i]);
cons(0 , 0 , N);
int l, r, q;
for(i = 0 ; i < Q ; i++)
{
scanf("%d %d %d", &l, &r, &q);
l--;
ll q1 = 0, q2 = 0;
ques(0 , 0 , N , l , r , q1 , q2);
//printf("%lld %lld\n", q1, q2);
ll ans = (q1 + Mod - q2) % Mod;
ans = ans * n2 % Mod * nC % Mod;
ans += (ll)(r - l) * (C + 1) % Mod * n2 % Mod;
check(ans);
printf("%lld\n", ans);
add(0 , 0 , N , l , r , q);
}
return 0;
}