精华内容
下载资源
问答
  • 透过树的启发

    2015-10-28 08:25:13
    路上 绿化还是做比较好,好多好多成排树木,其实习惯了看到了这种场景,一般也没太多感悟,但是今天做在车上,感觉眼睛似乎越发关注一棵一棵的树木,一幢一幢房子,好像不放过任何细小东西,当看到一...

    今天早上,坐在去上班的车子上,天气比较早,最近习惯了6点19就起床了,去上班也习惯了早去。路上的 绿化还是做的比较好的,好多好多成排的树木,其实习惯了看到了这种场景,一般也没太多感悟,但是今天做在车上,感觉眼睛似乎越发的关注一棵一棵的树木,一幢一幢的房子,好像不放过任何细小的东西,当看到一颗树木的时候,我问我自己,透过这棵树,你看到了什么,我说,我看到的是  “任何事物的存在,都有他存在的道理,他存在的道理要么是有它自身存在的意义,要么是为了他物存在而必须存在”,我相信树木也是有生命的,我想他的存在,可能就是因为这棵树之魂很享受成为树的这份喜悦,享受树的生活方式,而且他的存在是因为人的存在而存在,因为他也是是生命的创造者,没有它成就不了生命的延续。再看看我们这种高级生命,存在的意义,1.为了自己,2.其实也是因为某个人的存在而存在,所以你成就了爱情,成就了亲情,在爱情里,你是她或他存在的意义,在亲情里,你是你父母亲人眼里的心肝,所以透过这棵树,我发现其实万事万物都是相连的,直接的或者间接的,但是必定有联系!

    展开全文
  • 树的启发式合并

    2019-05-23 10:26:00
    树的启发式合并可以解决很多不涉及修改的子树查询问题。 每次向上合并时,轻链并入重链,可以使得总复杂度由\(O(n^2)\)变成\(O(n\log(n))\)。因为每次加入重链,子树大小都会翻倍。 例题:codeforces 600E 给定一棵...

    树的启发式合并可以解决很多不涉及修改的子树查询问题。

    每次向上合并时,轻链并入重链,可以使得总复杂度由\(O(n^2)\)变成\(O(n\log(n))\)。因为每次加入重链,子树大小都会翻倍。

    例题:codeforces 600E

    给定一棵树,每个节点都有一个颜色值。
    定义一种颜色值占领一棵子树,当且仅当这种颜色是这棵子树中出现最多的颜色。

    问每个节点为根的子树中,占领这棵子树的颜色值之和。

    代码

    #include <bits/stdc++.h>
    
    #define FOPI freopen("in.txt", "r", stdin)
    #define FOPO freopen("out.txt", "w", stdout)
    
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> pr;
    const int maxn = 1e5 + 100;
    
    int n;
    vector<int> v[maxn];
    map<int, int> col[maxn];
    LL ans[maxn];
    int maxt[maxn];
    
    void merge(int x, int y)
    {
        if (col[x].size() < col[y].size()) {
            swap(col[x], col[y]);
            ans[x] = ans[y];
            maxt[x] = maxt[y];
        }
    
        for (auto val : col[y]) {
            int a = val.first, b = val.second;
            col[x][a] += b;
    
            if (col[x][a] > maxt[x]) {
                maxt[x] = col[x][a];
                ans[x] = a;
            }
            else if (col[x][a] == maxt[x]) {
                ans[x] += a;
            }
        }
        col[y].clear();
    }
    
    void dfs(int x, int from)
    {
        for (int y : v[x]) {
            if (y == from) continue;
            dfs(y, x);
            merge(x, y);
        }
    }
    
    int main()
    {
        //FOPI;
    
        scanf("%d", &n);
        int x, y;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &x);
            col[i][x] = 1;
            ans[i] = x;
            maxt[i] = 1;
        }
    
        for (int i = 1; i <= n-1; i++) {
            scanf("%d%d", &x, &y);
            v[x].push_back(y), v[y].push_back(x);
        }
    
        dfs(1, 0);
    
        printf("%lld", ans[1]);
        for (int i = 2; i <= n; i++)
            printf(" %lld", ans[i]);
        puts("");
    }
    

    转载于:https://www.cnblogs.com/ruthank/p/10910428.html

    展开全文
  • 一棵 n(1≤n≤105)n(1\le n \le 10^5)n(1≤n≤105) 个结点的树,111 是根节点。一个结点结实程度是 ∑i=1k−1(ai+1−ai)2\sum_{i=1}^{k-1}(a_{i+1}-a_i)^2∑i=1k−1​(ai+1​−ai​)2 ,其中 aia_iai​ 为子树...

    阔力梯的树

    题意

    一棵 n(1n105)n(1\le n \le 10^5) 个结点的树,11 是根节点。一个结点的结实程度是 i=1k1(ai+1ai)2\sum_{i=1}^{k-1}(a_{i+1}-a_i)^2 ,其中 aia_i 为子树的结点编号按照升序排序。求每个结点的结实程度。

    解法

    离线的子树问题,考虑树上启发式合并。

    用一个 setset 来维护子树的所有结点,然后每次插入或者删除结点的时候,更新答案即可,注意分类讨论即可。

    代码

    #pragma region
    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <map>
    #include <queue>
    #include <set>
    #include <vector>
    using namespace std;
    typedef long long ll;
    #define tr t[root]
    #define lson t[root << 1]
    #define rson t[root << 1 | 1]
    #define rep(i, a, n) for (int i = a; i <= n; ++i)
    #define per(i, a, n) for (int i = n; i >= a; --i)
    #pragma endregion
    const int maxn = 1e5 + 5;
    int n;
    vector<int> g[maxn];
    int sz[maxn], son[maxn];
    int flag;
    ll ans[maxn], sum;
    set<ll> st;
    void dfs1(int u) {
        sz[u] = 1;
        for (auto v : g[u]) {
            dfs1(v);
            sz[u] += sz[v];
            if (sz[v] > sz[son[u]]) son[u] = v;
        }
    }
    void count(int u, int f, int val) {
        if (val == 1) st.insert(u);
        auto it = st.find(u);
        auto en = st.end();
        --en;
        if (it == st.begin()) {
            ++it;
            if (it != st.end()) sum += val * (*it - u) * (*it - u);
        } else if (it == en) {
            --it;
            sum += val * (*en - *it) * (*en - *it);
        } else {
            auto p = --it;
            ++it;
            auto q = ++it;
            sum += val * ((*q - u) * (*q - u) + (u - *p) * (u - *p) - (*q - *p) * (*q - *p));
        }
        if (val == -1) st.erase(st.find(u));
        for (auto v : g[u]) {
            if (v == f || v == flag) continue;
            count(v, u, val);
        }
    }
    void dfs(int u, int f, bool keep) {
        for (auto v : g[u]) {
            if (v == f || v == son[u]) continue;
            dfs(v, u, 0);
        }
        if (son[u]) {
            dfs(son[u], u, 1);
            flag = son[u];
        }
        count(u, f, 1);
        ans[u] = sum;
        flag = 0;
        if (!keep) {
            count(u, f, -1);
        }
    }
    int main() {
        scanf("%d", &n);
        rep(i, 2, n) {
            int f;
            scanf("%d", &f);
            g[f].push_back(i);
        }
        dfs1(1);
        dfs(1, 0, 0);
        rep(i, 1, n) printf("%lld\n", ans[i]);
    }
    
    展开全文
  • 题目大意:给出一棵树,每个节点都有一个编号,现在规定每个节点“结实程度”为其子树中所有编号排序后相邻两个数之差平方和,现在需要求出每个节点“结实程度” 题目分析:因为离线+对每个子树操作,...

    题目链接:点击查看

    题目大意:给出一棵树,每个节点都有一个编号,现在规定每个节点的“结实程度”为其子树中所有的编号排序后相邻两个数之差的平方和,现在需要求出每个节点的“结实程度”

    题目分析:因为离线+对每个子树的操作,所以可以用树上启发式合并nlogn解决问题, 对于每次更新/删除操作,因为题目的计算方法的前提是有序,并且每个编号两两都不互相重复,所以我们可以直接用一个set来维护,对于统计答案,我一开始用了一个很笨的方法,对于每个节点都遍历一遍set内的数,这样时间复杂度显然是n*n*logn的,肯定超时了,其实借助树上启发式合并不断传递的思想,对于每次更新的一个数,我们都可以在logn的时间复杂度内解决,具体实现就是先二分找到这个操作数的位置,并取出其相邻的两个数,减去之前的贡献,累加上新增加的贡献即可完成贡献,这样总时间复杂度为nlognlogn,而且牛客的评测机跑的好快,我用vector邻接表存边最后也才跑了300多ms

    在代码实现方面,关于对一个数维护答案的代码部分,增加时和删除时的代码是大同小异的,但我为了方便直接CV大法了,没有考虑到代码复用的问题,可能代码看起来比较冗杂

    代码:

    #include<iostream>
    #include<cstdio> 
    #include<string>
    #include<ctime>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    #include<queue>
    #include<map>
    #include<set>
    #include<cmath>
    #include<sstream>
    #include<unordered_map>
    using namespace std;
     
    typedef long long LL;
     
    const int inf=0x3f3f3f3f;
     
    const int N=1e5+100;
    
    vector<int>node[N];
    
    set<int>st;
    
    LL sum;
    
    int son[N],num[N];
    
    LL ans[N];
    
    bool vis[N];
    
    void dfs_son(int u)
    {
    	son[u]=-1;
    	num[u]=1;
    	for(auto v:node[u])
    	{
    		dfs_son(v);
    		num[u]+=num[v];
    		if(son[u]==-1||num[son[u]]<num[v])
    			son[u]=v;
    	}
    }
    
    void add(int num)
    {
    	set<int>::iterator it=st.lower_bound(num),start=st.begin(),end=st.end();
    	end--;
    	auto pre=it,next=it;
    	if(it!=start)
    		pre--;
    	if(it!=end)
    		next++;
    	if(pre!=it&&next!=it)//当前插入的数在中间
    	{
    		sum-=1LL*(*next-*pre)*(*next-*pre);
    		sum+=1LL*(*next-*it)*(*next-*it);
    		sum+=1LL*(*pre-*it)*(*pre-*it);
    	} 
    	else if(pre!=it)//在最后 
    	{
    		sum+=1LL*(*pre-*it)*(*pre-*it);
    	}
    	else if(next!=it)//在开头
    	{
    		sum+=1LL*(*next-*it)*(*next-*it);
    	}
    	else//只有一个数 
    	{
    		sum=0;
    	}
    }
    
    void del(int num)
    {
    	set<int>::iterator it=st.lower_bound(num),start=st.begin(),end=st.end();
    	end--;
    	auto pre=it,next=it;
    	if(it!=start)
    		pre--;
    	if(it!=end)
    		next++;
    	if(pre!=it&&next!=it)//当前删除的数在中间
    	{
    		sum+=1LL*(*next-*pre)*(*next-*pre);
    		sum-=1LL*(*next-*it)*(*next-*it);
    		sum-=1LL*(*pre-*it)*(*pre-*it);
    	} 
    	else if(pre!=it)//在最后 
    	{
    		sum-=1LL*(*pre-*it)*(*pre-*it);
    	}
    	else if(next!=it)//在开头
    	{
    		sum-=1LL*(*next-*it)*(*next-*it);
    	}
    	else//只有一个数 
    	{
    		sum=0;
    	}
    }
    
    void update(int u,int val)
    {
    	if(val==1)
    	{
    		st.insert(u);
    		add(u);
    	}
    	else
    	{
    		del(u);
    		st.erase(u);
    	}
    	for(auto v:node[u])
    	{
    		if(vis[v])
    			continue;
    		update(v,val);
    	}
    }
    
    void dfs(int u,int keep)
    {
    	for(auto v:node[u])
    	{
    		if(v==son[u])
    			continue;
    		dfs(v,0);
    	}
    	if(son[u]!=-1)
    	{
    		dfs(son[u],1);
    		vis[son[u]]=true;
    	}
    	update(u,1);
    	ans[u]=sum;
    	if(son[u]!=-1)
    		vis[son[u]]=false;
    	if(!keep)
    		update(u,-1);
    }
    
    int main()
    {
    //	freopen("input.txt","r",stdin);
    //	ios::sync_with_stdio(false);
    	int n;
    	scanf("%d",&n);
    	for(int i=2;i<=n;i++)
     	{
     		int fa;
     		scanf("%d",&fa);
     		node[fa].push_back(i);
    	}
    	dfs_son(1);
    	dfs(1,1);
     	for(int i=1;i<=n;i++)
     		printf("%lld\n",ans[i]);
     
     
     
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	return 0;
    }

     

    展开全文
  • 连边后分别在每一棵树上建立主席树,每一棵树每一个节点主席树维护从所在树根到当前节点路径上权值 合并过程用比较小树合并大比较大树上 求解询问关键:s=sz[L[x]]+sz[L[y]]...
  • //【Educational Codeforces Round 2E】【STL-map 启发式合并】Lomsat gelral 一棵树每点一个颜色问每个节点子树颜色众数之和 #include #include #include #include #include #include #include #include #...
  • 启发式合并

    2020-07-12 10:47:07
    树上启发式合并 前言: 今天又遇到启发式合并了,还没有写出来,还是...举一个例子,现在有一棵树,每个节点涂有一个颜色。需要统计每颗子树上哪种颜色最多。 暴力合并 nt n;//size of tree vector<int> tree[m
  • 就是给你一棵树,树上每个节点都有一个颜色,在你mmm次询问每次询问给你一个节点uuu和一个数字kkk,问你在uuu这颗子树里面又少种颜色结点个数是大于kkk; 解题思路: 看到子树问题我们最先考虑就是树上启发式合并,...
  • 人工智能—— 博弈树的启发式搜索

    千次阅读 2019-06-13 08:04:39
    一、概述 博弈概念 博弈是一类具有智能行为竞争活动,如下棋、战争等。...若把双人完备信息博弈过程用图表示出来,就得到一棵与/或,这种与/或被称为博弈。在博弈中,那些下一步该MAX走步结...
  • 启发式合并总结

    千次阅读 2018-11-30 14:09:45
    前言 某一天发现一道树上启发式合并裸题,但我不会写…… 学习并刷了两天题,是时候来写个总结了 正文 树上启发式合并(DSU on Tree),是一个在O(nlogn)O...题意简述:一棵树有n个结点,每个结点都是一种颜...
  • 一棵树,每个节点有一个权值。 任何两个不同的节点都会把他们权值的\(gcd\)告诉他们的\(LCA\)节点。问每个节点被告诉的最大的数。 题解 第一次接触到树的启发式合并。 用一个set维护每个节点权值的因子。 自下而上...
  • 【RxJava】种下一棵树RxJava

    千次阅读 2017-03-03 12:13:40
    对于RxJava了解从 扔物线 的一篇 给 Android 开发者 RxJava 详解 文章开始,记得当时看这篇文章花费整整个下午时间,看完之后一片雾水,但是也有所启发(也算是留下了个印象),今天再次打开了 给 Android...
  • 模板拿cf600E举例子,问题是给一棵有根树(rt==1),每个节点有一个颜色值,树的节点数和颜色值的范围都是1e5。对于每个节点我们定义其子树中数量最多的那个颜色值为主颜色(可以有多个并列),现要给出每个节点的主...
  • 题意:给一棵根为1的树,每次询问子树颜色种类数 思路:启发式合并,每次计算时如果是第一次出现就计算贡献,轻链话要消除贡献 #include<bits/stdc++.h> using namespace std; typedef long long ll; ...
  • 一棵树,每个点有一个权值。求这棵树的每一棵子树的众数权值之和,如果有多个众数那么都要统计。先考虑 O(n2)O(n^2)O(n2) 的暴力,对于每一棵子树,遍历这棵子树的所有点,用一个桶记录每一个数...
  • 题意:一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树最多颜色编号和。 dsu on tree简介: 在O(N^2)暴力做法中,我们用cnt记录每种颜色出现次数,对于每个结点,遍历这棵子...
  • 这种算法能够解决关于询问一棵树的子树的相关信息的问题。 算法的流程大概是这样:1、dfs将一棵树建好,将节点的size、dfs序、重儿子、该dfs序对应的节点这些信息处理好(其他的信息具体问题具体分析)。2、进入...
  • 求区间第kkk大我们是在序列上建主席,每线段代表个前缀和,那么求路径第kkk大,类比序列前缀和与上前缀和转化,我们可以在上建主席,每线段代表从个点到根路径上信息,这样我们就可以...
  • 树上启发式合并是某些神仙题目常见操作。 这里有一个讲得详细一点,不过为了深刻记忆,我还是再给自己讲一遍...然后咱们来考虑一个基础题:给出一棵树,每个节点有颜色,询问一些子树中不同颜色数量(颜色可...
  • 给定一棵树,每个节点上都有权值,每个节点答案为以当前节点为公共祖先节点且距离为k点对点权和之和 分析 如果没有固定根节点,可以用点分治来写,现在已经固定好1为根,所以可以考虑dsu on tree 我们转化...
  • 启发式合并模板

    2020-03-29 08:37:35
    模板拿cf600E举例子,问题是给一棵有根树(rt==1),每个节点有一个颜色值,树的节点数和颜色值的范围都是1e5。对于每个节点我们定义其子树中数量最多的那个颜色值为主颜色(可以有多个并列),现要给出每个节点的主...
  • 一棵树,每个点都有权值vi,求满足以下三个条件点对个数 这两个点不能互为祖先节点 这两个点之间最短距离不能超过k 这两个点最近公共祖先节点权值*2等于这两个点权值之和 分析 看到树上统计点对个数,...
  • 虽然深绘里家乡小村落对洪水有着顽固抵抗力,但也倒了几座老房子,几老树被连根拔起,以及田地里粮食被弄得片狼藉。 无奈深绘里和村民们只好等待救济粮来维生。 不过救济粮发放方式很特别。 首先村落...
  • 给你一棵带点权的树,每次查询 \(u\) 和 \(x\) ,求以 \(u\) 为根结点子树上结点与 \(x\) 异或后最大结果。 分析 看到子树,直接上启发式合并,看到异或,上 \(Trie\) 。 这道题就是两个经典题目结合了...
  • dsu on tree(树上启发式合并) ...简单了说就是对于这棵树的每个子树,找到哪个子树的重量(节点个数)最多。 重复利用 对于U节点。他的重子树V。 先对U的轻儿子递归求解轻儿子的答案,删除轻儿子统计的任何信息。
  • 一棵有点权的树。根节点是1号节点,让找两个点,然后保留这两个点到根节点路径,把其他点删了。使得图上剩余点权值异或和最大。 怎么说呢? 没干出来,,想到了字典求一对异或值最大点。 然后 求一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 475
精华内容 190
关键字:

一棵树的启发