刚开始想了一个很naive的分块加虚树的做法,不管时空复杂度还是代码复杂度都巨大
可以把问题转发成求
再推一下式子就得到
在树上维护一个主席树,最后一个sigma可以用链剖加线段树维护出来
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=200010,M=N*300;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
inline void read(ll &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
int type,n,q,cnt,G[N],p[N],top[N],size[N],son[N],fa[N];
struct edge{
int t,nx,w;
}E[N<<1];
inline void addedge(int x,int y,int z){
E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].w=z; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].w=z; G[y]=cnt;
}
int dpt[N];
ll dis[N],sdis[N];
void dfs1(int x,int f){
size[x]=1; fa[x]=f; dpt[x]=dpt[f]+1;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f){
dis[E[i].t]=dis[x]+E[i].w;
dfs1(E[i].t,x);
if(size[E[i].t]>size[son[x]]) son[x]=E[i].t;
size[x]+=size[E[i].t];
}
}
int lst[N],bg[N],ed[N],t;
void dfs2(int x,int tp){
top[x]=tp; lst[++t]=x; bg[x]=t;
if(son[x]) dfs2(son[x],tp);
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=fa[x] && E[i].t!=son[x]) dfs2(E[i].t,E[i].t);
ed[x]=t;
}
int tot1,tot2,ls[M],rs[M],rt1[N],rt2[N],sum[N*20],lss[N*20],rss[N*20];
ll tot[M];
void Add(int &g,int x,int l,int r){
int k=g; g=++tot2; lss[g]=lss[k]; rss[g]=rss[k]; sum[g]=sum[k]+1;
if(l==r) return ;
int mid=l+r>>1;
if(x<=mid) Add(lss[g],x,l,mid); else Add(rss[g],x,mid+1,r);
}
void Add(int &g,int x,int l,int r,ll y){
int k=g; g=++tot1; ls[g]=ls[k]; rs[g]=rs[k]; tot[g]=tot[k]+y;
if(l==r) return ;
int mid=l+r>>1;
if(x<=mid) Add(ls[g],x,l,mid,y); else Add(rs[g],x,mid+1,r,y);
}
inline void Modify(int &g1,int &g2,int x){
Add(g2,bg[x],1,n);
while(x){
Add(g1,bg[x],1,n,dis[x]); x=fa[top[x]];
}
}
void pfs(int x){
sdis[x]=sdis[fa[x]]+dis[p[x]];
rt1[x]=rt1[fa[x]]; rt2[x]=rt2[fa[x]];
Modify(rt1[x],rt2[x],p[x]);
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=fa[x]) pfs(E[i].t);
}
ll ans;
void PutAns(ll x){
if(x>=10) PutAns(x/10); putchar(x%10+'0');
}
inline int lca(int u,int v){
while(top[u]!=top[v]){
if(dpt[top[u]]return dpt[u]int g,int l,int r,int L,int R){
if(l==L && r==R) return tot[g];
int mid=L+R>>1;
if(r<=mid) return Query1(ls[g],l,r,L,mid);
else if(l>mid) return Query1(rs[g],l,r,mid+1,R);
else return Query1(ls[g],l,mid,L,mid)+Query1(rs[g],mid+1,r,mid+1,R);
}
int Query2(int g,int l,int r,int L,int R){
if(l==L && r==R) return sum[g];
int mid=L+R>>1;
if(r<=mid) return Query2(lss[g],l,r,L,mid);
else if(l>mid) return Query2(rss[g],l,r,mid+1,R);
return Query2(lss[g],l,mid,L,mid)+Query2(rss[g],mid+1,r,mid+1,R);
}
inline ll Query(int u,int k){
ll ret=sdis[u]+dpt[u]*dis[k]-2*Query2(rt2[u],bg[k],ed[k],1,n)*dis[k];
while(1){
if(k!=top[k]){
k=fa[k];
ret-=2*Query1(rt1[u],bg[top[k]],bg[k],1,n);
}
k=top[k];
if(!fa[k]) break;
ret-=2*dis[fa[k]]*(Query2(rt2[u],bg[fa[k]],ed[fa[k]],1,n)-Query2(rt2[u],bg[k],ed[k],1,n));
k=fa[k];
}
return ret;
}
inline ll Query(int u,int v,int k){
int LCA=lca(u,v);
return Query(u,k)+Query(v,k)-Query(LCA,k)-Query(fa[LCA],k);
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
read(type); read(n); read(q);
for(int i=1,x,y,z;ifor(int i=1;i<=n;i++) read(p[i]);
dfs1(1,0); dfs2(1,1); pfs(1);
while(q--){
ll u,v,k; read(u); read(v); read(k);
u^=ans*type; v^=ans*type; k^=ans*type;
PutAns(ans=Query(u,v,k)); putchar('\n');
}
return 0;
}