首页 > 其他分享 >洛谷P3258 [JLOI2014] 松鼠的新家

洛谷P3258 [JLOI2014] 松鼠的新家

时间:2024-10-09 22:44:24浏览次数:1  
标签:JLOI2014 洛谷 vis int P3258 lca return 300005 include

Problem

给定一棵树,再给出其在树上的移动顺序,从\(a_1\)开始,在\(a_n\)结束,求出每个节点最少需要经过多少次(终点即\(a_n\)的最后一次到达不算)。其中\(n\le3\times10^5\),\(1\le a_i\le n\)且保证a是1~n的排列

Solve

不难想到最少遍历的次数就是全走最短路,而一棵树中u->v的最短路必定是u->lca(u,v)->v
所以我们可以先跑一边tarjan求LCA,然后按照顺序遍历树即可。
但是测试点中大概率会通过类似链的树+叶子与根之间反复横跳的方法将程序的时间复杂度卡到\(O(n^2)\),需要考虑优化
不难想到虽然是一棵树,但是每次从一个点到下一个点也是对一条树上的链进行区间增加,所以我们可以定义\(f_i\)是从i号点到根有一条增加x的链,这样我们可以直接在两个点与lca之间增加了,最后dfs求后序遍历出的和即可

Code

//注意事项:lca(u,v)可能就是u或v,此时特判,且除了起点都会多算一次,要减去
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
int n,a[300005],f[300005],b[300005],lca[300005],q[300005],fa[300005],ans[300005];//lca[i]:i与前面点的lca
bool vis[300005];
vector<int> g[300005];
int find(int u){
    if(f[u]==u)return u;
    return f[u]=find(f[u]);
}
bool same(int u,int v){
    return find(u)==find(v);
}
bool unit(int u,int v){
    if(same(u,v))return false;
    f[v]=u;
    return true;
}
void dfs(int t){
    for(int i=0;i<g[t].size();i++){
        if(!vis[g[t][i]]){
            vis[g[t][i]]=1;
            fa[g[t][i]]=t;
            dfs(g[t][i]);
            unit(t,g[t][i]);
        }
    }
    if(vis[a[b[t]-1]]){
        lca[t]=find(a[b[t]-1]);
    }
    if(vis[a[b[t]+1]]){
        lca[a[b[t]+1]]=find(a[b[t]+1]);
    }
}
int dfs1(int t,int father){
    int sum=q[t];
    for(int i=0;i<g[t].size();i++){
        if(g[t][i]!=father){
            sum+=dfs1(g[t][i],t);
        }
    }
    ans[t]=sum;
    return sum;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[a[i]]=i;
    }
    for(int i=1,u,v;i<n;i++){
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    vis[1]=1;
    dfs(1);
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=n;i++){
        if(lca[a[i]]!=a[i]&&lca[a[i]]!=a[i-1]){
            q[a[i]]++;
            q[fa[lca[a[i]]]]--;
            q[a[i-1]]++;
            q[lca[a[i]]]--;
            //cout<<a[i]<<" "<<a[i-1]<<" "<<lca[a[i]]<<" "<<fa[lca[a[i]]]<<endl;
        }else{
            int x=lca[a[i]]==a[i]?a[i-1]:a[i];
            q[x]++;
            q[fa[lca[a[i]]]]--;
            //cout<<x<<" "<<fa[lca[a[i]]]<<endl;
        }
    }
    dfs1(1,0);
    for(int i=1;i<=n;i++){
        if(b[i]>=2)ans[i]--;
        cout<<ans[i]<<"\n";
    }
    return 0;
}

标签:JLOI2014,洛谷,vis,int,P3258,lca,return,300005,include
From: https://www.cnblogs.com/yiweixxs/p/18455300

相关文章

  • 洛谷 P7469 [NOI Online 2021 提高组] 积木小赛(字符串哈希)
    题目传送门解题思路读题后,我们可以发现,字母串  只能从两边删除,于是我们可以枚举一个区间 ,然后在字母串  中匹配(可以用指针来进行匹配),同时可以做字符串哈希去重。注意如果怕被卡,可以用双模哈希;记得开longlong代码#include<bits/stdc++.h>usingnamespacestd;......
  • 洛谷题单指南-字符串-P3375 【模板】KMP
    原题链接:https://www.luogu.com.cn/problem/P3375题意解读:给定两个字符串:原串s,模式串p,求p在s中出现的所有位置,并输出p的长度为1~p.size()的子串的最长相同真前、后缀的长度。解题思路:KMP模版题,分两问,第一问通过KMP核心算法实现,第二问输出模式串的Next数组内容,接下来一一解读。......
  • 洛谷P2323 [HNOI2006] 公路修建问题
    Problem给出n个点、m条边的无向连通图,每条边具有2个边权,一高一低,我们需要选择若干条边,使得图连通的情况下选择至少k条较高边权,输出选择的边中,边权最大值的最小值,输出答案的一半(保证偶数)Slove假设每条边只具有1条边权,答案显而易见,跑一遍最小生成树即可,因为最小生成树就是最小......
  • 洛谷P2513 逆序对数列
    Problem给定n,k,求得1~n中有多少种排列使得逆序对个数为k?(n,k<=1000)Solve考虑DP:设f[i][j]为i个数中逆序对数量为j的排列数量但因为我们并不知道我们这i个数到底是谁,难以通过以前的状态得到设f[i][j]为将i放入之前的排列后,逆序对数量为k的排列数此时我们发现可以确定前i-1......
  • 【模板】回文自动机(PAM)(洛谷P5496)
    #include<bits/stdc++.h>#defineendl'\n'#defineintllusingll=longlong;typedefunsignedlonglongull;usingnamespacestd;voidGordenGhost();constexprllN=5e5+7;namespacePAM{intsize,tot,last;//last:最新插入的字母的编号......
  • 洛谷 P3523 题解
    洛谷P3523[POI2011]DYN-Dynamite分析二分答案,问题转化为:对于给定的\(K\),选择尽可能少的节点,使得所有关键节点都被「覆盖」。对于一个关键节点,「覆盖」的定义为:存在一个被选择的点与这个关键节点的距离不大于\(K\)。方便起见,我们指定\(1\)号节点是这棵树的根节点。我们......
  • 20241006每日一题洛谷P1031
    对题目第一印象:贪心吧,或者纯模拟第一次贪心,由于左右端堆只能想内一堆移动,遂放弃第一次模拟,开多个数组,(可能还要用递归?),遂放弃于是求助如来佛祖:从逻辑上可以看出,第一堆缺或者多的牌只能移动到第二堆上当第一堆达到期望值时,第一堆便不能再做操作,于是,可以将第二堆作为第一堆来处理......
  • 20241002每日一题洛谷P1563
    粗看题目我靠,什么方向还变来变去的(哭泣核心思想:圈内右数,圈外左数为整体逆时针数;圈外右数,圈内左数为整体顺时针数运用结构体就有了第一版源码:structpeople{ intface; charname[12];};intmain(){ intm,n; scanf("%d%d",&n,&m); peoplea[10010]; for(inti......
  • [题解][洛谷P3584] LAS
    题目描述有n个蛋糕和n个人,每个蛋糕的热量是Ci。第i个人可以选择吃第i或第i+1个蛋糕,第n个人可以选择吃第n或第1个蛋糕。若一个蛋糕被两个人吃,那么每个人得到的热量是Ci/2.若一个人改变自己的选择,得到的热量增加,那么他会不满意。试输出让所有人满意的解,输出每个人吃蛋糕的序号......
  • [题解][洛谷P1578] 奶牛浴场
    题目描述在长宽为L,W的二维平面上有n个障碍点,试找到一个不覆盖任何障碍点(但点可以在边缘线上的)面积最大的矩形(长宽均与坐标轴平行)。输出面积。题意分析n的范围在5e3,考虑O(n2)的做法。易得面积最大的矩形四条边要么有障碍点,要么覆盖的边界。否则四条边可以继续扩展,面积会变得更......