zoukankan      html  css  js  c++  java
  • 【树链剖分】【dfs序】【LCA】【分类讨论】Codeforces Round #425 (Div. 2) D. Misha, Grisha and Underground

    一棵树,q次询问,每次给你三个点a b c,让你把它们选做s f t,问你把s到f +1后,询问f到t的和,然后可能的最大值是多少。

    最无脑的想法是链剖线段树……但是会TLE。

    LCT一样无脑,但是少一个log,可以过。

    正解是分类讨论,

    如果t不在lca(s,f)的子树内,答案是dis(lca(s,f),f)。

    如果t在lca(s,f)的子树内,并且dep(lca(s,t))>dep(lca(f,t)),答案是dis(lca(s,t),f);

    否则答案是dis(lca(f,t),f)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define N 100010
    int n,m,ans;
    int v[N<<1],next[N<<1],first[N],en;
    void AddEdge(int U,int V)
    {
        v[++en]=V;
        next[en]=first[U];
        first[U]=en;
    }
    int fa[N],dep[N],top[N],son[N],siz[N];
    int Ls[N],Rs[N],tot;
    void dfs(int U)
    {
        siz[U]=1;
        for(int i=first[U];i;i=next[i])
          if(v[i]!=fa[U])
            {
              fa[v[i]]=U;
              dep[v[i]]=dep[U]+1;
              dfs(v[i]);
              siz[U]+=siz[v[i]];
              if(siz[v[i]]>siz[son[U]])
                son[U]=v[i];
            }
    }
    void df2(int U)
    {
    	Ls[U]=++tot;
        if(son[U])
          {
            top[son[U]]=top[U];
            df2(son[U]);
          }
        for(int i=first[U];i;i=next[i])
          if(v[i]!=fa[U]&&v[i]!=son[U])
            {
              top[v[i]]=v[i];
              df2(v[i]);
            }
        Rs[U]=tot;
    }
    int lca(int U,int V)
    {
        while(top[U]!=top[V])
          {
            if(dep[top[U]]<dep[top[V]])
              swap(U,V);
            U=fa[top[U]];
          }
        if(dep[U]>dep[V])
          swap(U,V);
        return U;
    }
    const int c[7][4]={{0,0,0,0},{0,1,2,3},{0,1,3,2},{0,2,1,3},{0,2,3,1},{0,3,1,2},{0,3,2,1}};
    int calc(int U,int V){
    	int tmp=dep[lca(U,V)];
    	return dep[U]+dep[V]-tmp-tmp+1;
    }
    int main()
    {
        int b[4],x;
        scanf("%d%d",&n,&m);
        for(int i=2;i<=n;++i)
          {
            scanf("%d",&x);
            AddEdge(x,i);
            AddEdge(i,x);
          }
        top[1]=dep[1]=1;
        dfs(1);
        df2(1);
        for(int i=1;i<=m;++i){
        	int ans=0;
        	for(int j=1;j<=3;++j){
        		scanf("%d",&b[j]);
        	}
        	for(int j=1;j<=6;++j){
        		int lcasf=lca(b[c[j][1]],b[c[j][2]]);
        		if(Ls[b[c[j][3]]]<Ls[lcasf] || Ls[b[c[j][3]]]>Rs[lcasf]){
        			ans=max(ans,calc(lcasf,b[c[j][2]]));
        		}
        		else{
        			int lcast=lca(b[c[j][1]],b[c[j][3]]);
        			int lcaft=lca(b[c[j][2]],b[c[j][3]]);
        			if(dep[lcast]>dep[lcaft]){
        				ans=max(ans,calc(lcast,b[c[j][2]]));
        			}
        			else{
        				ans=max(ans,calc(lcaft,b[c[j][2]]));
        			}
        		}
        	}
        	printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    【转】Uiautomator Api浅析
    【转】UiAutomator简要介绍
    后台自动启动appium
    adb通过wifi连接Android设备
    Python字符串处理和输入输出
    OJ题目输出的生成
    Weka的使用和二次开发(朴素贝叶斯及其属性选择)
    PointNet++论文理解和代码分析
    VGG-16复现
    二维偏序-最长上升子序列的两种求解方式
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/7231921.html
Copyright © 2011-2022 走看看