首页 > 其他分享 >树上倍增

树上倍增

时间:2023-01-20 22:34:23浏览次数:41  
标签:树上 minn start int sum ne ++ 倍增

  • https://codeforces.com/contest/702/problem/E

题意:

  • 给一个n个点,n条有向边,n个权值的图,每个点一条出边
  • 问所有的点按着有向边走k的权值和,还有k条边上的最小权值是多少,并输出

思路:

  • 经典的倍增题目
  • 先利用倍增找出子$2^p$的子节点是哪个,记为$ne[i][p]$
  • 然后就可以记$sum[i][p],minn[i][p]$为子$2^p$步的权值和,和最小权值
  • 最后就是对$k$二进制从低位到高位分解
  • 具体倍增就是$ne[i][p] = ne[ne[i][p-1]][p-1]$(从低往高递推),其他两个同理

#include<bits/stdc++.h>
#define debug1(a) cout<<#a<<'='<< a << endl;
#define debug2(a,b) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<endl;
#define debug3(a,b,c) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<"  "<<#c<<" = "<<c<<endl;
#define debug4(a,b,c,d) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<"  "<<#c<<" = "<<c<<"  "<<#d<<" = "<<d<<endl;
#define debug5(a,b,c,d,e) cout<<#a<<" = "<<a<<"  "<<#b<<" = "<<b<<"  "<<#c<<" = "<<c<<"  "<<#d<<" = "<<d<<"  "<<#e<<" = "<<e<<endl;
#define endl "\n"
#define fi first
#define se second

#define int long long
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;

//#pragma GCC optimize(3,"Ofast","inline")
//#pragma GCC optimize(2)
const int N = 1e5+10,P = 35;

int edge[N],w[N];
int ne[N][P];
int minn[N][P],sum[N][P];

void solve() 
{
    int n,k;cin >> n >> k;

    for(int i = 0;i < n;i ++)
        cin >> edge[i];
    for(int i = 0;i < n;i ++)
        cin >> w[i];
    
    for(int p = 0;p < P;p ++)
    {
        for(int i = 0;i < n;i ++)
        {
            if(p) ne[i][p] = ne[ne[i][p-1]][p-1];
            else ne[i][p] = edge[i];
        }
    }

    for(int p = 0;p < P;p ++)
    {
        for(int i = 0;i < n;i ++)
        {
            if(p) 
            {
                sum[i][p] = sum[i][p-1] + sum[ne[i][p-1]][p-1];
                minn[i][p] = min(minn[i][p-1],minn[ne[i][p-1]][p-1]);
            }
            else sum[i][p] = minn[i][p] = w[i];
        }
    }

    for(int i = 0;i < n;i ++)
    {
        int res_sum = 0,res_minn = 1e9;
        for(int start = i,j = 0;j < P;j ++)if(k >> j & 1)
        {
            res_sum += sum[start][j];
            res_minn = min(res_minn,minn[start][j]);
            start = ne[start][j];
        }
        cout << res_sum << " " << res_minn << endl;
    }
}

signed main()
{
    /*
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    */
    int T = 1;//cin >> T;

    while(T--){
        //puts(solve()?"YES":"NO");
        solve();
    }
    return 0;

}
/*

*/

 

标签:树上,minn,start,int,sum,ne,++,倍增
From: https://www.cnblogs.com/cfddfc/p/17063343.html

相关文章

  • 【题解】P4768 [NOI2018] 归程(树上倍增,Kruskal 重构树,dijkstra)
    【题解】P4768[NOI2018]归程作为一道NOI的D1T1,放在现在或许难度不够(?),但可能在Kruskal重构树还未普及的当时,还是相对来说比较难的一道题吧。写篇题解记录一下。题......
  • 倍增
    概述略。真让我一周把这些车出来不如~了我。真想整的话就...例题P4155[SCOI2015]国旗计划题意略。我一开始把题审错了以为是链...另外这里是要接力的,即覆盖......
  • 树上分块解决限制距离的树上 DP 问题([NOI2014] 购票)
    [NOI2014]购票大家好,我喜欢暴力数据结构,所以我用分块过了此题。转移方程很简单:\[f_u=\min_{d_u-d_v\leql_u}{(d_u-d_v)\timesp_u+q_u+f_v}\]\[f_u=d_u\timesp_u+q......
  • P6374 「StOI-1」树上询问
    P6374「StOI-1」树上询问Description给定一颗\(n\)个节点的树,有\(q\)次询问。每次询问给一个参数三元组\((a,b,c)\),求有多少个\(i\)满足这棵树在以\(i\)为......
  • 算法学习笔记(3): 倍增与ST算法
    倍增目录倍增查找洛谷P2249重点变式练习快速幂ST表扩展-运算扩展-区间变式答案倍增,字面意思即”成倍增长“他与二分十分类似,都是基于”2“的划分思想那么具体是怎......
  • 23寒假集训二1月3号(单调队列+倍增)
    vjudge上面的题当天是我负责讲题所以写了一下博客,优先队列永远的敌人,一直没太整清楚前置知识倍增//倍增//给定一个数列,共有n个正数,现在有m次询问,每次询问给出一个t,求满......
  • 树上路径问题
    P5588 小猪佩奇爬树:P5588小猪佩奇爬树-洛谷|计算机科学教育新生态(luogu.com.cn)v用来存储各个颜色的节点一.v[i].size()=0时,不再赘述二.v[i].size()=1时,此......
  • 有用的技巧(前缀、差分、位运算、快速幂、倍增)
    前缀和一维前缀和 for(inti=1;i<=n;++i){pre[i]=pre[i-1]+a[i];}二维前缀和 for(inti=1;i<=n;++i){......
  • 树形 dp 与树上问题
    NFLS集训笔记20220802-树形dp进阶与树上问题综合\(\text{ByDaiRuiChen007}\)I.洛谷[P2585]-三色二叉树\(\text{Link}\)思路分析简单题,建出树后暴力枚举当前......
  • 树上启发式合并
    树上启发式合并\(\text{ByDaiRuiChen007}\)一、算法简介在解决树上问题时,我们经常遇到需要统计多个节点各自的子树信息的情况,对于一般暴力统计的\(\Theta(n^2)\)复杂......