CF 686D. Kay and Snowflake

给你一个树N个点,再给出Q个询问,问以x为根的子树中,重心是哪个?
2≤n≤300000,1≤q≤30000

Sol:
从下到上,根据性质做一下.
1:如果某个点x,其子树y的大小超过总结点个数一半,则重心在y这个子树中。
2:如果某个树的重心点,其上方点的个数多于其下方点的,则重心要上移

#include <bits/stdc++.h>
using namespace std;
const int N = 300000+10;
int n,q;
vector<int> G[N]; ///存图
int ans[N];       ///答案
int son[N];       ///包括自身在内有多少子树结点
int fa[N];        ///输入用,同时代表这个点的父亲

void dfs(int u){
    ans[u] = u;//当只有一个点时,重心为其自己
    son[u] = 1;
    for(int i = 0;i < G[u].size();i++){
        int v = G[u][i];
        dfs(v);
        son[u] += son[v];
    }
    for(int i = 0;i < G[u].size();i++)
        if(son[G[u][i]]*2 > son[u])
		//如果有一个子树超过总个数一半,则重心在这个子树中
		    ans[u] = ans[G[u][i]];
    while((son[u]-son[ans[u]])*2 > son[u])
    //如果当前重心上方的点,比它下方的点要多,则重心要进行移动
        ans[u] = fa[ans[u]];
}

int main(void)
{
    scanf("%d%d",&n,&q);
    for(int i = 2;i <= n;i++){
        scanf("%d",&fa[i]);
        G[fa[i]].push_back(i);
    }
    dfs(1);
    for(int i = 1;i <= q;i++){
        int qq;
        scanf("%d",&qq);
        printf("%d\n",ans[qq]);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/cutemush/p/11830897.html

时间: 2024-08-02 04:05:43

CF 686D. Kay and Snowflake的相关文章

Codeforces 686 D - Kay and Snowflake

D - Kay and Snowflake 思路: 树的重心 利用重心的一个推论,树的重心必定在子树重心的连线上. 然后利用重心的性质,可知,如果有一颗子树的大小超过整棵树的大小的1/2,那么树的重心一定在这颗子树上. 利用以上两条,可知: 如果没有一颗子树的大小超过整棵树的大小的1/2,那么就可以以根节点为树的重心, 不然就从 超过1/2大小的子树 的重心 到 根节点 之间找整棵树的重心. 因为不会找重复的点,所以退化的复杂度为O(n) #include<bits/stdc++.h> usi

codeforces 685B Kay and Snowflake 树的重心

分析:就是找到以每个节点为根节点的树的重心 树的重心可以看这三篇文章: 1:http://wenku.baidu.com/link?url=yc-3QD55hbCaRYEGsF2fPpXYg-iO63WtCFbg4RXHjERwk8piK3dgeKKvUBprOW8hJ7aN7h4ZC09QE9x6hYV3lD7bEvyOv_l1E-ucxjHJzqi 2:http://fanhq666.blog.163.com/blog/static/81943426201172472943638/ 3:ht

Codeforces Round #359 (Div. 2) D. Kay and Snowflake

题目链接:传送门 题目大意:给你n个点,n-1条边连接所有点构成一棵树,1是树根,有m次询问,对于每次询问的点x,在x及x的子树中找出一个点,使删去这个点,所得包含元素最多的联通分块 所含有的点的个数<=原x及x子树的点之和的1/2.输出这个点. 题目思路:比赛时想了一种方法,递归求每个点的连通度然后找子树所含点中最大的联通度向上不断更新,不过方法错了,比如给一条链的话,询问树根1,答案就错了 后来补题的时候始终是在考虑怎么样将子树中删去一个点能产生最大连通块所含点数保存并更新上去,在这就卡住了

Codeforces 686 D.Kay and Snowflake (dfs 树的重心)

题目链接: http://codeforces.com/problemset/problem/685/B 题意: 给你n个点,以1为根,然后给你2-n的节点的父亲节点编号.问你每一颗子树的重心是哪一个节点. 思路: 有定理:把两个树通过一条边相连得到一个新的树,那么新的树的重心在连接原来两个树的重心的路径上. 考虑树的重心在哪个部分,一定是在当前节点u的最大子树v中,假设我们已经知道了子树v的重心ans[v],那么u的重心呢?就是在ans[v]这个节点到u的路径上. 代码: #include<b

CodeForces 685B Kay and Snowflake

树的重心,树形$dp$. 记录以$x$为$root$的子树的节点个数为$sz[x]$,重儿子为$son[x]$,重心为$ans[x]$. 首先要知道一个结论:以$x$为$root$的子树的重心$ans[x]$,一定在$ans[son[x]]$到$x$的路径上,即以$x$的重儿子为根的子树的重心到$x$的路径上. 因此,只要从节点$ans[son[x]]$依次往$father$枚举就可以了. 如果枚举到节点$g$,发现$g$节点满足$sz\left[ {son\left[ g \right]} \

Kay and Snowflake CodeForces - 685B (重心, 好题)

大意:给定有根树, 求每个子树的重心 我太菜了啊, 只能想到暴力树剖, 然而这就是个B题, 感觉树剖+线段树二分还是挺难写的..... 看了题解发现重心一定在重儿子与根的树链上, 重心最多上跳n-1次, 直接暴力就行 原文地址:https://www.cnblogs.com/uid001/p/10618657.html

微信 {&quot;errcode&quot;:40029,&quot;errmsg&quot;:&quot;invalid code, hints: [ req_id: Cf.y.a0389s108 ]&quot;}

{"errcode":40029,"errmsg":"invalid code, hints: [ req_id: Cf.y.a0389s108 ]"} 问题:微信网页授权后,获取到 openid 了,一刷新又没了 微信网页授权获取到的 code 只能使用一次(5分钟内有效),使用一次后,马上失效. 页面授权跳转成功,根据 code 也换取到 openid 了. 此时刷新页面,并不会再次进行授权,而是直接刷新了一下上一次授权跳转后的链接,带的还是

CF with friends and user&#39;s influence considered on NYC data(updated Aug,11st)

Here is the code link: https://github.com/FassyGit/LightFM_liu/blob/master/U_F1.py I use NYC data as other experimens. The split of the training data was seperated by the timeline, and I have normalised the interaction matrix by replacing the checkin

CF 750

今天CF打的块残废了     就是一废物 A 在24点之前到 直接模拟即可 #include<stdio.h> #include<algorithm> #include<cstring> #include<string> #include<cmath> using namespace std; #define LL long long #define MAXN 1010 #define inf 1000000000.0 int main() {