丢人 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)大常数跑不过 B Z O J BZOJ BZOJ老爷机
考虑如果当前询问区间为
[
l
,
r
]
[l,r]
[l,r]
我们从
l
−
1
l-1
l−1和
r
+
1
r+1
r+1的叶子节点往上走到
l
c
a
(
l
−
1
,
r
+
1
)
lca(l-1,r+1)
lca(l−1,r+1)
把
l
−
1
l-1
l−1往上所有右儿子记下来,
r
+
1
r+1
r+1所有左儿子记下来
那得到的区间就是要求的定位区间
但是每次定位显然也是不行的
考虑如何维护这样一堆儿子
以右儿子为例
考虑用类似括号序列的方法
当
d
f
s
dfs
dfs到某个点的时候,把
(
r
c
,
1
)
(rc,1)
(rc,1)加到序列里
d
f
s
dfs
dfs左儿子,再次回来的时候把
(
r
c
,
−
1
)
(rc,-1)
(rc,−1)加到序列里
再
d
f
s
dfs
dfs右儿子
可以发现这样
l
−
1
,
l
c
a
l-1,lca
l−1,lca之间的路径就变成了序列上的一段区间
现在问题就变成了给定一个序列上的区间
询问区间所有点到某一个指定点的距离
又
d
i
s
(
u
,
v
)
=
d
e
p
(
u
)
+
d
e
p
(
v
)
−
2
∗
d
e
p
(
l
c
a
)
dis(u,v)=dep(u)+dep(v)-2*dep(lca)
dis(u,v)=dep(u)+dep(v)−2∗dep(lca)
两个
d
e
p
dep
dep很好维护
我们考虑如何维护
∑
d
e
p
(
l
c
a
)
\sum dep(lca)
∑dep(lca)
就是
L
c
a
Lca
Lca这道题
复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)大常数被 O ( n l o g n ) O(nlogn) O(nlogn)踩爆了
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
const int N=800005;
struct ask{
int l,coef,id;
};
vector<ask> q[2][N<<1];
vector<int> e[N];
int pos[2][N],dfn[2],in[2][N],val[2][N],*ps,*vl;
int dn;
int son[N][2],idx[N],rt,qry[N];
int n,m,tot;
ll ans[N];
int build(int l,int r){
int u=++tot;
if(l==r){idx[l]=u;return u;}
int mid=read();
son[u][0]=build(l,mid);
son[u][1]=build(mid+1,r);
e[u].pb(son[u][0]),e[u].pb(son[u][1]);
return u;
}
void dfs1(int u){
if(son[u][1])
ps[++dfn[0]]=son[u][1],vl[dfn[0]]=1;
in[0][u]=dfn[0];
if(son[u][0])dfs1(son[u][0]);
if(son[u][1])
ps[++dfn[0]]=son[u][1],vl[dfn[0]]=-1,dfs1(son[u][1]);
}
void dfs2(int u){
if(son[u][0])
ps[++dfn[1]]=son[u][0],vl[dfn[1]]=1;
in[1][u]=dfn[1];
if(son[u][1])dfs2(son[u][1]);
if(son[u][0])
ps[++dfn[1]]=son[u][0],vl[dfn[1]]=-1,dfs2(son[u][0]);
}
namespace Tr{
ll tr[N<<2];int tag[N<<2];
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
inline void pushup(int u){
tr[u]=tr[lc]+tr[rc];
}
inline void pushdown(int u,int l,int r){
if(!tag[u])return ;
tag[lc]+=tag[u],tag[rc]+=tag[u];
tr[lc]+=1ll*(mid-l+1)*tag[u],tr[rc]+=1ll*(r-mid)*tag[u];
tag[u]=0;
}
void update(int u,int l,int r,int st,int des,int k){
if(st<=l&&r<=des){tag[u]+=k,tr[u]+=1ll*(r-l+1)*k;return;}
pushdown(u,l,r);
if(st<=mid)update(lc,l,mid,st,des,k);
if(mid<des)update(rc,mid+1,r,st,des,k);
pushup(u);
}
ll query(int u,int l,int r,int st,int des){
if(st<=l&&r<=des){return tr[u];}
pushdown(u,l,r);ll res=0;
if(st<=mid)res+=query(lc,l,mid,st,des);
if(mid<des)res+=query(rc,mid+1,r,st,des);
pushup(u);return res;
}
inline void clear(){
memset(tr,0,sizeof(tr)),memset(tag,0,sizeof(tag));
}
int In[N],dfn,siz[N],hson[N],top[N],dep[N],fa[N];
void dfs1(int u){
siz[u]=1;
for(auto &v:e[u]){
fa[v]=u,dep[v]=dep[u]+1;
dfs1(v),siz[u]+=siz[v];
if(siz[v]>siz[hson[u]])hson[u]=v;
}
}
void dfs2(int u,int tp){
In[u]=++dfn,top[u]=tp;
if(hson[u])dfs2(hson[u],tp);
for(auto &v:e[u]){
if(v==hson[u])continue;
dfs2(v,v);
}
}
inline void init(){
dep[rt]=1,dfs1(rt),dfs2(rt,rt);
}
inline void pathupdate(int u,int v,int k){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
update(1,1,dfn,In[top[u]],In[u],k);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
update(1,1,dfn,In[v],In[u],k);
}
inline ll pathquery(int u,int v){
ll res=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
res+=query(1,1,dfn,In[top[u]],In[u]);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
res+=query(1,1,dfn,In[v],In[u]);
return res;
}
inline int Lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
}
inline void query(int u,int l,int r,int id){
l=idx[l-1],r=idx[r+1];
int lca=Tr::Lca(l,r);
q[0][in[0][l]].pb(ask{u,1,id});
q[0][in[0][lca]].pb(ask{u,-1,id});
q[1][in[1][r]].pb(ask{u,1,id});
q[1][in[1][lca]].pb(ask{u,-1,id});
}
inline void calc(int ID,int *pos,int dfn,int *val,int *in){
ll sum0=0,sum1=0;
for(int i=1;i<=dfn;i++){
sum0+=val[i],sum1+=Tr::dep[pos[i]]*val[i];
Tr::pathupdate(rt,pos[i],val[i]);
for(auto &x:q[ID][i]){
ll res=sum0*Tr::dep[x.l];
res+=sum1,res-=2ll*Tr::pathquery(x.l,rt);
ans[x.id]+=res*x.coef;
}
}
Tr::clear();
}
signed main(){
n=read();
build(1,n);
idx[0]=++tot,idx[n+1]=++tot;
rt=++tot;son[rt][0]=idx[0],son[rt][1]=++tot;
e[rt].pb(idx[0]),e[rt].pb(tot);
son[tot][0]=1,son[tot][1]=idx[n+1];
e[tot].pb(1),e[tot].pb(idx[n+1]);
Tr::init();
ps=pos[0],vl=val[0];
dfs1(rt),ps=pos[1],vl=val[1];
dfs2(rt),m=read();
for(int i=1;i<=m;i++){
int u=read(),l=read(),r=read();
query(u,l,r,i);
}
calc(0,pos[0],dfn[0],val[0],in[0]),calc(1,pos[1],dfn[1],val[1],in[1]);
for(int i=1;i<=m;i++)cout<<ans[i]<<'\n';exit(0);
}