题目链接:点我啊╭(╯^╰)╮
参考博客:点我啊╭(╯^╰)╮
题目大意:
线段树的左右子区间为
、
定义
为在长度为
的线段树上标号为
的叶子结点的深度,求
解题思路:
为 有
个叶子的线段树的叶子深度和
为 叶子深度叶子
的和
为 叶子深度乘
的和
分别为它们的前缀和
根据线段树的特性,将每颗线段树分为两颗子树
根据性质可得出以下递推式:
当
为奇数时,
、
当
为偶数时,
、
证明过程自己脑补
核心:神TM简单的分形题
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
#define x first
#define y second
using namespace std;
typedef long long ll;
using pii = pair <int,int>;
const ll p = 998244353;
int T;
ll L, R, inv2, inv6;
map <ll, ll> f, h, g;
ll qpow(ll a, ll b){
ll ret = 1;
while(b){
if(b & 1) ret = ret * a % p;
a = a * a % p;
b >>= 1;
}
return ret;
}
ll sum1(ll n){
return (n %= p) * (n + 1) % p * inv2 % p;
}
ll sum2(ll n){
return (n %= p) * (n + 1) % p * (n*2 + 1) % p * inv6 % p;
}
ll sum3(ll n){
return (sum1(n) + sum2(n)) % p * inv2 % p;
}
void dfs(ll n){
if(f.count(n)) return;
if(n <= 1) {
f[n] = h[n] = g[n] = n;
return;
}
if(n & 1){
ll l = (n + 1) >> 1, r = n >> 1;
dfs(l), dfs(r);
f[n] = (f[l] + f[r]*3 + sum1(n) - 1 + p) % p;
h[n] = ((h[l]*2 - f[l]) + h[r]*2 + (h[r]*2 + f[r]) + h[r]*2 + sum2(n) - 1 + p) % p;
g[n] = ((g[l] + g[r]) + (g[r] + h[r]) + (g[r] + h[r] + f[r]) + sum3(n) - 1 + p) % p;
} else {
ll l = n >> 1, r = l - 1;
dfs(l), dfs(r);
f[n] = (f[l]*3 + f[r] + sum1(n) - 1 + p) % p;
h[n] = (h[l]*2 + (h[l]*2 - f[l]) + h[l]*2 + (h[r]*2 + f[r]) + sum2(n) - 1 + p) % p;
g[n] = (g[l]*2 + (g[l] + h[l]) + (g[r] + h[r] + f[r]) + sum3(n) - 1 + p) % p;
}
}
ll cal(ll x){
dfs(x);
return g[x];
}
int main() {
inv2 = qpow(2, p - 2);
inv6 = qpow(6, p - 2);
scanf("%d", &T);
while(T--){
scanf("%lld%lld", &L, &R);
printf("%lld\n", (cal(R) - cal(L - 1) + p * 2) % p);
}
}