• 【Vijos-P1935】不可思议的清晨-树上倍增+LCA+分类讨论


    测试地址:不可思议的清晨

    做法:我是按照这位前辈的做法做的:前辈的题解

    里面有一句话我特别赞同:树上乱搞用倍增。事实证明,树上倍增在很多树的题目中都有很大用处,用了它,在往树根方向“走动”时时间效率可以从O(n)缩为O(log n),非常优秀。而在这个题目中,我们要分类讨论,设两个点x和y的LCA(最近公共祖先)为t,则分为3种情况:

    1.x和y到t的距离相同,这个时候t就是区分离x近和离y近的点的分界点,这时候只要从x和y尽量往t走,又不至于走到t即可(也就是走到t的儿子),这时以它们为根的子树上点权的和就是答案。

    2.x到t的距离比y到t的距离长,这时分界点一定在x到t的路径上,用倍增找出这个分界点,分界点的往x方向的点是离x较近的,书中其余的和x与y距离不相等的点就离y较近,用点权之和加加减减就可以了。

    3.x到t的距离比y到t的距离短,同2,将x和y转换一下位置即可。

    因此,我们只需先随便找一个树根,然后从树根DFS,记录:dep[x]:点x在树中的深度,倍增用;fa[x][i]:点x的第2^i代祖先,倍增用;d[x]:点x到树根的距离;s[x]:以x为根的子树上的点权之和。然后按照上述方法,对于每个询问分类讨论即可。

    不过在抄题解之后还是有一点疑问,例如题目中数据范围指出边的长度可能为0,但在程序中好像没有体现分析这种情况的代码,不知是我水平比较低还是如何,如果有大神看到这个,求告知。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    int n,q,tot=0,first[100010]={0},fa[100010][21]={0},dep[100010]={0};
    ll val[100010],s[100010],d[100010];
    struct edge {int v,next;ll d;} e[200010];
    
    void insert(int a,int b,int c)
    {
      e[++tot].v=b;
      e[tot].d=c;
      e[tot].next=first[a];
      first[a]=tot;
    }
    
    void dfs(int v)
    {
      s[v]=val[v];
      for(int i=first[v];i;i=e[i].next)
        if (e[i].v!=fa[v][0])
        {
          fa[e[i].v][0]=v;
       	  dep[e[i].v]=dep[v]+1;
    	  d[e[i].v]=d[v]+e[i].d;
    	  dfs(e[i].v);
    	  s[v]+=s[e[i].v];
        }
    }
    
    int lca(int x,int y)
    {
      if (dep[x]<dep[y]) swap(x,y);
      for(int i=19;i>=0;i--)
        if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
      for(int i=19;i>=0;i--)
        if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
      if (x==y) return x;
      else return fa[x][0];
    }
    
    void work()
    {
      while(q--)
      {
        int x,y;
    	scanf("%d%d",&x,&y);
    	if (x==y) {printf("0 0
    ");continue;}
        int t=lca(x,y);
    	if (d[x]-d[t]==d[y]-d[t])
    	{
    	  int tmpx,tmpy;
    	  ll ansx,ansy;
    	  tmpx=x;
    	  for(int i=19;i>=0;i--)
    	    if (dep[fa[tmpx][i]]>dep[t]) tmpx=fa[tmpx][i];
    	  ansx=s[tmpx];
    	  tmpy=y;
    	  for(int i=19;i>=0;i--)
    	    if (dep[fa[tmpy][i]]>dep[t]) tmpy=fa[tmpy][i];
    	  ansy=s[tmpy];
    	  printf("%lld %lld
    ",ansx,ansy);
    	}
    	else if (d[x]-d[t]>d[y]-d[t])
    	{
    	  int tmp,tmpx,tmpy;
    	  ll ansx,ansy;
    	  tmpx=x;
    	  for(int i=19;i>=0;i--)
    	    if (dep[fa[tmpx][i]]>dep[t]&&d[fa[tmpx][i]]+d[y]-(d[t]<<1)>d[x]-d[fa[tmpx][i]]) tmpx=fa[tmpx][i];
    	  ansx=s[tmpx];
    	  tmpy=fa[tmpx][0];
    	  for(int i=19;i>=0;i--)
    	    if (dep[fa[tmpy][i]]>dep[t]&&d[tmpy]==d[tmpx]) tmpy=fa[tmpy][i];
    	  tmp=tmpx;
    	  for(int i=19;i>=0;i--)
    	    if (dep[fa[tmp][i]]>dep[tmpy]) tmp=fa[tmp][i];
    	  ansy=s[1]-s[tmp];
    	  printf("%lld %lld
    ",ansx,ansy);
    	}
    	else
    	{
    	  int tmp,tmpx,tmpy;
    	  ll ansx,ansy;
    	  tmpy=y;
    	  for(int i=19;i>=0;i--)
    	    if (dep[fa[tmpy][i]]>dep[t]&&d[fa[tmpy][i]]+d[x]-(d[t]<<1)>d[y]-d[fa[tmpy][i]]) tmpy=fa[tmpy][i];
    	  ansy=s[tmpy];
    	  tmpx=fa[tmpy][0];
    	  for(int i=19;i>=0;i--)
    	    if (dep[fa[tmpx][i]]>dep[t]&&d[tmpx]==d[tmpy]) tmpx=fa[tmpx][i];
    	  tmp=tmpy;
    	  for(int i=19;i>=0;i--)
    	    if (dep[fa[tmp][i]]>dep[tmpx]) tmp=fa[tmp][i];
    	  ansx=s[1]-s[tmp];
    	  printf("%lld %lld
    ",ansx,ansy);
    	}
      }
    }
    
    int main()
    {
      scanf("%d",&n);
      for(int i=1,a,b,c;i<n;i++)
      {
        scanf("%d%d%d",&a,&b,&c);
    	insert(a,b,c);insert(b,a,c);
      }
      for(int i=1;i<=n;i++) scanf("%lld",&val[i]);
      scanf("%d",&q);
      
      dep[1]=d[1]=0;
      dfs(1);
      for(int j=1;j<=19;j++)
        for(int i=1;i<=n;i++)
    	  fa[i][j]=fa[fa[i][j-1]][j-1];
      
      work();
      
      return 0;
    }
    


  • 相关阅读:
    防简单攻击iptables策略
    Iptables 防火墙常用配置
    9个常用iptables配置实例
    NFS服务的端口分配
    docker参数--restart=always的作用
    nginx的proxy_pass路径转发规则最后带/问题
    查看tomcat进程启动了多少个线程
    Tomcat 普通用户启动
    SSH远程执行脚本tomcat未启动
    mysql 前缀索引
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793862.html
Copyright © 2020-2023  润新知