P6025 线段树 题解

Luogu

Description.

定义 \(f(i)\) 表示长度为 \(n\) 的序列构成的线段树占的节点数量。
\(\bigoplus_{i=l}^rf(i)\)\(l\le r\le 10^{15}\)

Solution.、

首先答案差分,相当于要求 \(g(k)=\bigoplus_{i=1}^kf(i)\)
考虑 \(i\rightarrow i+1\) 会发生什么,会分裂一个叶子节点多出两个叶子节点。
如果 \(2^i+2t(t<2^i)\) 分裂成 \(2^i+2t+1\) 时每次肯定分裂了一个左儿子。
所以肯定有 \(f(2^i+2t)=f(2^i+2t+1)\),然后就消掉了。
剩下的肯定是 \(f(n)\) 以及 \(f(2^i)\)\(f(2^i+1)\)
前两个没有浪费,肯定是 \(2n-1\),着重需要求一下 \(f(n)\)

肯定有 \(f(n)=f(\left\lfloor\frac n2\right\rfloor)+2^{dep}\),直接递归就行了。

Coding.

点击查看代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
inline char bit(ll a) {return (a&(-a))==a;}
inline int getd(ll n) {int ps=0;while((1ll<<ps)<n) ps++;return ps;}
inline ll getf(ll n,int dep) {return bit(n)||bit(n-1)?2*n-1:getf(n>>1,dep-1)+(1ll<<dep);}
inline ll getg(ll pos)
{
	if(pos==0) return pos;
	ll rs=0;for(int l=0;(1ll<<l)<=pos;l++) {rs^=(2ll<<l)-1;if(pos!=(1ll<<l)) rs^=(2ll<<l)+1;}
	if(bit(pos)||bit(pos-1)||pos&1) return rs;else return rs^getf(pos,getd(pos));
}
int main() {ll l,r;return read(l,r),printf("%lld\n",getg(r)^getg(l-1)),0;}
posted @ 2021-11-02 15:52  Peal_Frog  阅读(28)  评论(0编辑  收藏  举报