基地
Description
有一棵点数为 n n 的树,号节点为根节点,对于剩下的任意节点 x x 他的父亲为,同时给出三个常数 a,b,c a , b , c , x x 到它父亲的道路长度为,接下来有 m m 轮操作,每次操作会删除一颗子树,每个操作后,需要回答两个询问,1、找到一个点使得所有点到它的距离最短(如果有多个的话则为编号最小的那个) 2、输出最短的距离模。
Data Constrains
n≤1018 m≤104 a,b,c≤109 n ≤ 10 18 m ≤ 10 4 a , b , c ≤ 10 9
Solution
若没有第二个询问,那答案显然为整棵树的重心,求重心的话需要构造一个函数
ask_size(o)
a
s
k
_
s
i
z
e
(
o
)
表示以
o
o
为根的子树大小,可以注意到如果不在以
o
o
为根的子树内,那以为根的子树就是一棵完全二叉树,否则只有最底层需要特殊计算,同时动态开点记下子树大小已经被修改过的点的当前
size
s
i
z
e
。
现在考虑维护第二个询问,一样需要维护一个函数
ask_total(o)
a
s
k
_
t
o
t
a
l
(
o
)
表示以
o
o
为根的子树内的所有点经过以o为根的子树内的边到达根节点的路径总长,对于这个函数可以将整棵子树分成层,对每一层的贡献分别求和即可。一样动态开点记下子树内贡献已经被修改过的点的
total
t
o
t
a
l
。
时间复杂度
O(m log2 n)
O
(
m
l
o
g
2
n
)
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)
using namespace std;
typedef long long ll;
const ll N=1e3,mo=998244353,n2=(mo+1)>>1,n6=(mo+1)/6;
map<ll,bool> done;
map<ll,ll> sz,size;
ll d[N],n,m,xx,a,b,c;
inline ll cf2(ll o)
{
o=o%mo;
return o*(o+1)%mo*(2*o+1)%mo*n6%mo;
}
inline ll cf1(ll o)
{
o=o%mo;
return o*(o+1)%mo*n2%mo;
}
inline ll lj(ll le,ll ri)
{return (a*(cf2(ri)-cf2(le-1)+mo)+b*(cf1(ri)-cf1(le-1)+mo)+(ri-le+1)%mo*c)%mo;}
inline ll count(ll x)
{
x=x%mo;
return (a*x%mo*x%mo+b*x%mo+c)%mo;
}
inline ll len(ll x)
{
int ok=1;
fo(i,1,d[0])if(x==d[i]){
ok=0; break;
}
ll v=x,ans=1;
for(;v*2+1<=n;v=v*2+1)ans=ans*2+1;
if(ok==1)return ans;
if(v==n)return ans;
v=v*2+1; ans=ans*2+1;
return ans-v+n;
}
inline ll js(ll x)
{
int ok=1;
fo(i,1,d[0])if(x==d[i]){
ok=0; break;
}
ll v=x,u=x,ans=0;
for(;v*2<=n;)v=v<<1,u=(u<<1)^1;
if(ok==1){
ll cs=1;
for(;v!=x;v>>=1,u>>=1,cs=(cs*2+1)%mo)
ans=(ans+lj(v,u)*cs)%mo;
}else{
ll c1=3,c2,c3=1,k=n; ans=lj(v,n);
if(k&1)c2=3;else c2=2;
for(k>>=1,v>>=1,u>>=1;k!=x;k>>=1,v>>=1,u>>=1){
if(k>v)ans=(ans+lj(v,k-1)*c1)%mo;
ans=(ans+count(k)*c2)%mo;
if(k<u)ans=(ans+lj(k+1,u)*c3)%mo;
if(k&1)c2=(c2+c1+1)%mo;else c2=(c2+c3+1)%mo;
c3=(c3*2+1)%mo; c1=(c1*2+1)%mo;
}
}
return ans;
}
int main()
{
cin>>n>>m>>a>>b>>c;
ll op=n;
for(;op;op>>=1)d[++d[0]]=op;
ll zh=js(1);
fo(i,1,m){
scanf("%lld",&xx);
if(done[xx]==false){
ll kk=xx;int ok=1;
for(;kk;kk>>=1)if(done[kk]==true){
ok=0; break;
}
done[xx]=true;
if(ok){
ll del=sz[xx],kk=xx;
del=(js(xx)-del+mo)%mo;
ll tot=0,dx=(len(xx)-size[xx])%mo;
for(;kk;kk>>=1){
sz[kk]=(sz[kk]+tot*dx+del)%mo;
tot=(tot+count(kk))%mo;
}
del=len(xx)-size[xx]; kk=xx;
for(;kk;kk>>=1)size[kk]=size[kk]+del;
}
}
ll dq=(zh-sz[1]+mo)%mo,x=1,lef=len(1)-size[1];
for(;x*2<=n;){
if(x*2==n){
if(lef-2*size[n]<0&&!done[n])dq=(dq+(lef-2*(1-size[n]))%mo*count(n)%mo+mo)%mo,x=n;
break;
}else{
ll ls=x<<1,rs=ls^1,d1=(lef-(len(ls)-size[ls])*2),d2=(lef-(len(rs)-size[rs])*2);
if(d1<0&&!done[ls])dq=(dq+d1%mo*count(ls)%mo+mo)%mo,x=ls;
else if(d2<0&&!done[rs])dq=(dq+d2%mo*count(rs)%mo+mo)%mo,x=rs;
else break;
}
}
printf("%lld %lld\n",x,dq);
}
}