zoukankan      html  css  js  c++  java
  • [hdu6995]Travel on Tree

    问题即查询将其按照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 }
    View Code
  • 相关阅读:
    转:win2000/2003 Discuz生存环境搭建及基础优化
    http://db.grussell.org 测试答案 1
    转:linux系统的主机做代理服务器
    C# code 0002
    Welcome to .NET BY C#
    几篇关于Visual Studio Team Foundation Server (TFS) 安装的文章
    VS2003不知道怎么不能编译C文件
    Kaspersky 更新修复
    入行性能测试两个月
    WMI 注册表 StdRegProv
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15097496.html
Copyright © 2011-2022 走看看