问题即查询将其按照dfs序排序后,相邻两点(包括首尾)的距离和
考虑使用莫队+set维护,时间复杂度为$o(nsqrt{n}log n)$,无法通过
进一步的,注意到删除是可以用链表实现的,因此考虑回滚莫队:
仍以$sqrt{n}$对原序列分块,并以左端点所在块升序为第一关键字、右端点降序为第二关键字排序
在访问到一个块时,先将莫队的左右端点设置为该块的左端点和$n$(需要求出这个区间对应的链表),显然此时这个块内右端点的移动只有删除,左端点只需要在每一次操作后回到该块左端点即可
更具体的,在本题中,即要支持:
1.$o(sqrt{n})$次查询一个大区间对应的链表,可以用桶排来实现
2.$o(nsqrt{n})$次删除操作,只需要将其前驱和后继连上即可
3.$o(nsqrt{n})$次撤销(删除)操作,在删除时记录其前驱后继,并还原即可(注意要先移动右端点、再移动左端点、最后还原,避免右端点的移动影响其前驱后继)
现在即实现了$o(nsqrt{n})$的维护链表,但还需要支持快速求相邻两点的距离(也即$lca$)
这是比较简单的,考虑tarjan求lca的做法:维护一个序列,在dfs过程中进入递归和搜索完某个儿子后加入自己,那么即查询$x$第一次出现和$y$第一次出现的位置中深度的最小值,使用ST表即可
(注意实现常数,由于操作基数较大,很小的常数也会有很大的影响)
综上,总复杂度为$o(nsqrt{n})$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define mod 998244353 5 #define ll long long 6 #define pii pair<int,int> 7 #define fi first 8 #define se second 9 int E,t,n,m,K,x,y,z,head[N],dfn[N],idfn[N],dep[N],Dfn[N<<1],pos[N],vis[N],pre[N],nex[N]; 10 ll ans[N]; 11 pii v[N]; 12 struct Edge{ 13 int nex,to,len; 14 }edge[N<<1]; 15 struct Data{ 16 int l,r,id; 17 bool operator < (const Data &k)const{ 18 return (l/K<k.l/K)||(l/K==k.l/K)&&(r>k.r); 19 } 20 }q[N]; 21 struct ST{ 22 int lg[N<<1],mn[N<<1][20]; 23 void build(){ 24 lg[0]=-1; 25 for(int i=1;i<(n<<1);i++){ 26 lg[i]=lg[i>>1]+1; 27 mn[i][0]=dep[Dfn[i]]; 28 } 29 for(int i=1;i<=lg[(n<<1)-1];i++) 30 for(int j=1;j<=(n<<1)-(1<<i);j++)mn[j][i]=min(mn[j][i-1],mn[j+(1<<i-1)][i-1]); 31 } 32 int get(int x,int y){ 33 if (x>y)swap(x,y); 34 int m=lg[y-x+1]; 35 return min(mn[x][m],mn[y-(1<<m)+1][m]); 36 } 37 }F; 38 void add(int x,int y,int z){ 39 edge[E]=Edge{head[x],y,z}; 40 head[x]=E++; 41 } 42 void dfs(int k,int fa,int s){ 43 dfn[k]=++dfn[0]; 44 idfn[dfn[0]]=k; 45 dep[k]=s; 46 Dfn[++Dfn[0]]=k; 47 pos[k]=Dfn[0]; 48 for(int i=head[k];i!=-1;i=edge[i].nex) 49 if (edge[i].to!=fa){ 50 dfs(edge[i].to,k,s+edge[i].len); 51 Dfn[++Dfn[0]]=k; 52 } 53 } 54 int dis(int x,int y){ 55 return dep[x]+dep[y]-(F.get(pos[x],pos[y])<<1); 56 } 57 int dis_dfn(int x,int y){ 58 return dis(idfn[x],idfn[y]); 59 } 60 void add(int x,pii o){ 61 pre[x]=o.fi,nex[x]=o.se; 62 pre[nex[x]]=nex[pre[x]]=x; 63 } 64 void dec(int x){ 65 int l=pre[x],r=nex[x]; 66 ans[0]-=(ll)dis_dfn(l,x)+dis_dfn(x,r)-dis_dfn(l,r); 67 pre[r]=l,nex[l]=r; 68 } 69 int main(){ 70 scanf("%d",&t); 71 while (t--){ 72 scanf("%d%d",&n,&m); 73 E=dfn[0]=Dfn[0]=0; 74 for(int i=1;i<=n;i++)head[i]=-1; 75 for(int i=1;i<n;i++){ 76 scanf("%d%d%d",&x,&y,&z); 77 add(x,y,z); 78 add(y,x,z); 79 } 80 dfs(1,0,0); 81 F.build(); 82 for(int i=1;i<=m;i++){ 83 scanf("%d%d",&q[i].l,&q[i].r); 84 q[i].id=i; 85 } 86 K=(int)sqrt(n); 87 sort(q+1,q+m+1); 88 for(int i=0,j=1;i<=n/K;i++){ 89 ans[0]=0; 90 for(int k=1;k<=n;k++)vis[k]=0; 91 int l=max(i*K,1),r=n,lst=n; 92 for(int k=l;k<=r;k++)vis[dfn[k]]=1; 93 while (!vis[lst])lst--; 94 for(int k=1;k<=n;k++) 95 if (vis[k]){ 96 pre[k]=lst; 97 nex[lst]=k; 98 ans[0]+=dis_dfn(lst,k); 99 lst=k; 100 } 101 while ((j<=m)&&(q[j].l/K==i)){ 102 while (r>q[j].r)dec(dfn[r--]); 103 ans[q[j].id]=ans[0]; 104 while (l<q[j].l){ 105 v[l]=make_pair(pre[dfn[l]],nex[dfn[l]]); 106 dec(dfn[l++]); 107 } 108 swap(ans[q[j++].id],ans[0]); 109 while (l>max(i*K,1)){ 110 l--; 111 add(dfn[l],v[l]); 112 } 113 } 114 } 115 for(int i=1;i<=m;i++)printf("%lld ",ans[i]); 116 } 117 return 0; 118 }