题目描述
其中
n
<
=
1
0
5
,
m
<
=
1
0
4
n<=10^5,m<=10^4
n<=105,m<=104
题解
发现
S
[
l
,
r
]
S[l,r]
S[l,r]上的点是上图中根须部分
考虑如何将左侧点找出来,右侧是类似的
首先将一个点(区间)的父亲设为紧挨着这个区间并且是最长的区间
然后就会发现要找的左侧点会是,这样新建的树的一条链
二次转化
对于树上一条链可以转化为括号序上的一段区间
转化后的题意
给出一棵树,求编号在一段区间内的两两距离和
解法1
简单结论
d
i
s
(
a
,
b
)
=
d
e
p
(
a
)
+
d
e
p
(
b
)
−
2
d
e
p
(
l
c
a
(
a
,
b
)
)
dis(a,b)=dep(a)+dep(b)-2dep(lca(a,b))
dis(a,b)=dep(a)+dep(b)−2dep(lca(a,b))
根据简单结论就可以转化为求两两l
l
c
a
lca
lca的深度和
对于序列先分块,枚举每一个块,然后用
O
(
n
)
O(n)
O(n)时间处理处对于每个点与这些块内点的
l
c
a
lca
lca深度和
这样就可以处理出整块与整块和散块与整块之间的值
对于散块与散块之间的值,就
O
(
n
)
O(n)
O(n)建虚树,在虚树上算(但是这样常数会很大,不知道有没有更简单的方法)
时间复杂度
O
(
n
1.5
)
O(n^{1.5})
O(n1.5)
小优化
如果散块中的点个数大于这个块中的总点数的 1 2 \frac{1}{2} 21,那么就可以先加上这个块,然后再减去剩下的点
解法2
可以不用将树上路径转化为欧拉序上区间
对于树可以树上链分块,具体操作就是对于深度为阈值的倍数且子树大小大于等于阈值的点设为关键点
对于每个关键点到最近祖先关键点的点形成一块,按照和序列分块一样的方法做,只不过就比较难用到序列上的小优化了
code
#include<bits/stdc++.h>
#define fo(i,a,b)for(int i=a,_e=b;i<=_e;++i)
#define fd(i,a,b)for(int i=b,_e=a;i>=_e;--i)
#define ll long long
#define pb push_back
using namespace std;
const int M=4e4+100,G=100;
int n,nn,q,rt,ts,a,b,c,d,A,B,C,D;
int a0,a1,b0,b1,c0,c1,d0,d1;
int le[M],ri[M],s[M][2],dy[M];
int ld[M],de[M],fa[M],hv[M];
int L[M],R[M],su[M];
int dds;
ll ans;
struct nod{int x,c,q;}dd[M],ee[M];
namespace graph{
int fa[M],de[M],en[M];
int es,fi[M],lg[M],lc[17][M],K;
int dl[M],ds,x;
int T[256],T2[256],s[M],ss,sfa[M],sd[M],sds;
int cc[M],qq[M];
vector<int>e[M];
void link(int x,int y){e[x].pb(y);e[y].pb(x);}
#define cmin(a,b)(de[a]<de[b]?a:b)
int lca(int x,int y){
x=fi[x];y=fi[y];
if(x>y)swap(x,y);
K=lg[y-x];
return cmin(lc[K][x],lc[K][y-(1<<K)+1]);
}
void dfs(int x){
dl[++ds]=x;
de[x]=de[fa[x]]+1;lc[0][++es]=x;fi[x]=es;
fo(i,0,e[x].size()-1)if(e[x][i]!=fa[x])
fa[e[x][i]]=x,dfs(e[x][i]),lc[0][++es]=x;
en[x]=es;
}
void init(){
dfs(1);
fo(i,2,es)lg[i]=lg[i>>1]+1;
fo(i,1,lg[es]){
int nx=1<<i-1;
fo(j,1,es-nx+1)lc[i][j]=cmin(lc[i-1][j],lc[i-1][j+nx]);
}
}
void pre(){
fo(i,1,4)su[nn+i]=0;
fd(i,2,ds)x=dl[i],su[fa[x]]+=su[x];
fo(i,2,ds)x=dl[i],su[x]+=su[fa[x]];
}
bool cmp(nod x,nod y){return fi[x.x]<fi[y.x];}
void get_tree(){
if(dds<32){
stable_sort(dd+1,dd+dds+1,cmp);
}else{
memset(T,0,256*4);
memset(T2,0,256*4);
fo(i,1,dds)x=fi[dd[i].x],++T[x&255],++T2[x>>8];
fo(i,1,255)T[i]+=T[i-1],T2[i]+=T2[i-1];
fd(i,1,dds)ee[T[fi[dd[i].x]&255]--]=dd[i];
fd(i,1,dds)dd[T2[fi[ee[i].x]>>8]--]=ee[i];
}
int zs=0;
fo(i,1,dds){
if(dd[i].x!=ee[zs].x)ee[++zs]=(nod){dd[i].x,0,0};
ee[zs].c+=dd[i].c;ee[zs].q+=dd[i].q;
}
fo(i,1,zs)dd[i]=ee[i];
ss=0;sds=0;
fo(i,1,zs){
x=dd[i].x;
cc[x]+=dd[i].c;
qq[x]+=dd[i].q;
if(!ss){
s[++ss]=x;
continue;
}
if(en[s[ss]]>fi[x]){
s[++ss]=x;
continue;
}
for(;ss&&en[s[ss]]<fi[x];)sfa[s[ss]]=s[ss-1],sd[++sds]=s[ss],--ss;
int lc=lca(s[ss+1],x);
sfa[s[ss+1]]=lc;
if(lc!=s[ss])s[++ss]=lc;
s[++ss]=x;
}
fd(i,1,ss)sfa[s[i]]=s[i-1],sd[++sds]=s[i];
fo(i,1,sds){
x=sd[i];
ans+=(ll)(de[x]-de[sfa[x]])*cc[x]*qq[x];
cc[sfa[x]]+=cc[x];
qq[sfa[x]]+=qq[x];
}
fo(i,1,sds)cc[sd[i]]=qq[sd[i]]=0;
}
}
struct tree{
int fa[M],fh[M],eu[M],fi[M],es,ct[M];
ll su[M];
vector<int>e[M];
void link(int x,int y){e[x].pb(y);fa[y]=x;}
void dfs(int x){
eu[++es]=x;fh[es]=1;fi[x]=es;
fo(i,0,e[x].size()-1)dfs(e[x][i]);
eu[++es]=x;fh[es]=-1;
}
void init(){
dfs(nn+1);
fo(i,1,es){
ct[i]+=ct[i-1]+fh[i];
su[i]+=su[i-1]+fh[i]*graph::de[eu[i]];
}
}
}T[2];
int Bk,be[M+5],sta[M/G+5],end[M/G+5],E,_n,cnt1,cnt2;
int v[2][M/G+5][2][M+5];
ll v2[2][M/G+5][2][M/G+5];
ll sum1,sum2;
void get_id(int &v,int l,int r){
v=++ts;le[v]=l;ri[v]=r;
if(!L[l])L[l]=v;
if(!R[r])R[r]=v;
if(l==r){
dy[l]=v;
return;
}
int m;scanf("%d",&m);
get_id(s[v][0],l,m);
get_id(s[v][1],m+1,r);
}
void dfs(int x){
de[x]=de[fa[x]]+1;ld[x]=1;
fo(o,0,1)if(s[x][o]){
int y=s[x][o];
fa[y]=x;
dfs(y);
ld[x]+=ld[y];
if(ld[y]>ld[hv[x]])hv[x]=y;
}
}
void dfs2(int x,int tp){
ld[x]=tp;
if(!hv[x])return;
dfs2(hv[x],tp);
fo(o,0,1)if(s[x][o]&&s[x][o]!=hv[x])dfs2(s[x][o],s[x][o]);
}
int get_lca(int x,int y){
for(;ld[x]!=ld[y];x=fa[ld[x]])if(de[ld[x]]<de[ld[y]])swap(x,y);
return de[x]<de[y]?x:y;
}
void work(int &a,int &b,int &A,int &B,int &ct,ll &su){
a=dy[a-1];b=dy[b+1];
A=get_lca(a,b);
B=s[A][0];
A=s[A][1];
A=T[0].fi[A]+1;a=T[0].fi[a]-1;
B=T[1].fi[B]+1;b=T[1].fi[b]-1;
ct=(A<=a?T[0].ct[a]-T[0].ct[A-1]:0)+(B<=b?T[1].ct[b]-T[1].ct[B-1]:0);
su=(A<=a?T[0].su[a]-T[0].su[A-1]:0)+(B<=b?T[1].su[b]-T[1].su[B-1]:0);
}
void get_ans1(int o,int u,int a,int A,int c,int C,int a0,int a1,int c0,int c1){
a=be[a]-1+a1;A=be[A]-a0;c=be[c]-1+c1;C=be[C]-c0;
if(A<a&&C<c)
ans+=v2[o][a][u][c]-v2[o][a][u][C]-v2[o][A][u][c]+v2[o][A][u][C];
}
void qu(int o,int u,int a,int A,int c,int C,int a0,int a1,int c0,int c1){
int be0=be[C]-c0,be1=be[c]-1+c1;
if(be0<be1){
if(be[a]==be[A])
if(a0){
fo(i,sta[be[A]],A-1)ans-=v[u][be1][o][i]-v[u][be0][o][i];
fo(i,a+1,end[be[a]])ans-=v[u][be1][o][i]-v[u][be0][o][i];
}else
fo(i,A,a)ans+=v[u][be1][o][i]-v[u][be0][o][i];
else{
if(a0)
fo(i,sta[be[A]],A-1)ans-=v[u][be1][o][i]-v[u][be0][o][i];
else
fo(i,A,end[be[A]])ans+=v[u][be1][o][i]-v[u][be0][o][i];
if(a1)
fo(i,a+1,end[be[a]])ans-=v[u][be1][o][i]-v[u][be0][o][i];
else
fo(i,sta[be[a]],a)ans+=v[u][be1][o][i]-v[u][be0][o][i];
}
}
}
void get_ans2(int o,int u,int a,int A,int c,int C,int a0,int a1,int c0,int c1){
if(a<A||c<C)return;
qu(o,u,a,A,c,C,a0,a1,c0,c1);
qu(u,o,c,C,a,A,c0,c1,a0,a1);
}
void get_dl(int a,int A,int o,int u,int a0,int a1){
if(a<A)return;
if(be[a]==be[A]){
if(a0){
fo(i,sta[be[A]],A-1)if(T[o].eu[i]<=nn)dd[++dds]=u?(nod){T[o].eu[i],0,-T[o].fh[i]}:(nod){T[o].eu[i],-T[o].fh[i],0};
fo(i,a+1,end[be[a]])if(T[o].eu[i]<=nn)dd[++dds]=u?(nod){T[o].eu[i],0,-T[o].fh[i]}:(nod){T[o].eu[i],-T[o].fh[i],0};
}else
fo(i,A,a)if(T[o].eu[i]<=nn)dd[++dds]=u?(nod){T[o].eu[i],0,T[o].fh[i]}:(nod){T[o].eu[i],T[o].fh[i],0};
}else{
if(a0){
fo(i,sta[be[A]],A-1)if(T[o].eu[i]<=nn)dd[++dds]=u?(nod){T[o].eu[i],0,-T[o].fh[i]}:(nod){T[o].eu[i],-T[o].fh[i],0};
}else
fo(i,A,end[be[A]])if(T[o].eu[i]<=nn)dd[++dds]=u?(nod){T[o].eu[i],0,T[o].fh[i]}:(nod){T[o].eu[i],T[o].fh[i],0};
if(a1){
fo(i,a+1,end[be[a]])if(T[o].eu[i]<=nn)dd[++dds]=u?(nod){T[o].eu[i],0,-T[o].fh[i]}:(nod){T[o].eu[i],-T[o].fh[i],0};
}else
fo(i,sta[be[a]],a)if(T[o].eu[i]<=nn)dd[++dds]=u?(nod){T[o].eu[i],0,T[o].fh[i]}:(nod){T[o].eu[i],T[o].fh[i],0};
}
}
void init2(){
s[nn+1][0]=nn+2;s[nn+1][1]=nn+4;
s[nn+2][0]=nn+3;s[nn+2][1]=rt;
R[0]=nn+3;R[n]=nn+2;L[n+1]=nn+4;
dy[0]=nn+3;dy[n+1]=nn+4;
fo(i,1,nn){
T[0].link(L[ri[i]+1],i);
T[1].link(R[le[i]-1],i);
}
T[0].link(L[1],nn+3);
T[0].link(nn+4,nn+2);
T[0].link(nn+1,nn+4);
T[1].link(nn+2,nn+4);
T[1].link(nn+1,nn+2);
T[1].link(nn+1,nn+3);
T[0].init();T[1].init();
dfs(nn+1);dfs2(nn+1,nn+1);
}
void get_op(int &a0,int &a1,int A,int a){
a0=a1=0;
if(a<A)return;
if(be[a]==be[A]){
if((end[be[a]]-sta[be[a]])-(a-A)<a-A)a0=1,a1=1;
}else{
if(A-sta[be[A]]<end[be[A]]-A)a0=1;
if(end[be[a]]-a<a-sta[be[a]])a1=1;
}
}
int main(){
freopen("segment.in","r",stdin);
freopen("segment.out","w",stdout);
cin>>n>>q;nn=n*2-1;
get_id(rt,1,n);
fo(i,2,nn)scanf("%d%d",&a,&b),graph::link(a,b);
graph::init();
init2();
E=T[0].es;Bk=100;
fo(i,1,E)be[i]=i/Bk+1,(!sta[be[i]]?sta[be[i]]=i:0),end[be[i]]=i;
_n=be[E];
fo(o,0,1)
fo(i,1,_n){
memset(su,0,(E+1)*4);
fo(j,sta[i],end[i])
su[T[o].eu[j]]+=T[o].fh[j];
graph::pre();
fo(u,0,1)
fo(j,1,E){
v[o][i][u][j]=v[o][i-1][u][j]+su[T[u].eu[j]]*T[u].fh[j];
v2[o][i][u][be[j]]+=v[o][i][u][j];
}
}
fo(o,0,1)fo(i,1,_n)
fo(u,0,1)fo(j,1,_n)
v2[o][i][u][j]+=v2[o][i][u][j-1];
for(;q--;){
scanf("%d%d%d%d",&a,&b,&c,&d);
ans=0;
work(a,b,A,B,cnt1,sum1);
work(c,d,C,D,cnt2,sum2);
get_op(a0,a1,A,a);
get_op(b0,b1,B,b);
get_op(c0,c1,C,c);
get_op(d0,d1,D,d);
get_ans1(0,0,a,A,c,C,a0,a1,c0,c1);
get_ans1(0,1,a,A,d,D,a0,a1,d0,d1);
get_ans1(1,0,b,B,c,C,b0,b1,c0,c1);
get_ans1(1,1,b,B,d,D,b0,b1,d0,d1);
get_ans2(0,0,a,A,c,C,a0,a1,c0,c1);
get_ans2(0,1,a,A,d,D,a0,a1,d0,d1);
get_ans2(1,0,b,B,c,C,b0,b1,c0,c1);
get_ans2(1,1,b,B,d,D,b0,b1,d0,d1);
dds=0;
get_dl(a,A,0,0,a0,a1);
get_dl(b,B,1,0,b0,b1);
get_dl(c,C,0,1,c0,c1);
get_dl(d,D,1,1,d0,d1);
graph::get_tree();
printf("%lld\n",sum1*cnt2+sum2*cnt1-ans*2);
}
}