noi.ac #525 神树的权值

mcfx神仙的题qwq

题目链接:戳我

首先,我们知道30%的分还是挺好做的
直接枚举根,然后dfs一遍以\(O(n)\)的时间复杂度求出来有多少神仙点
代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define MAXN 100010
using namespace std;
int n,t;
int a[MAXN],head[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
inline void add(int from,int to)
{
    edge[++t].nxt=head[from],edge[t].to=to;
    head[from]=t;
}
namespace subtask1
{
    int ans;
    int kkk[MAXN];
    inline void search(int x,int pre,int maxx)
    {
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(v==pre) continue;
            if(a[v]>maxx) kkk[v]=1;
            search(v,x,max(maxx,a[v]));
        }
    }
    inline void solve()
    {
        for(int p=1;p<=n;p++)
        {
            ans=0;
            for(int i=1;i<=n;i++) kkk[i]=0;
            kkk[p]=1;
            search(p,0,a[p]);
            for(int i=1;i<=n;i++)
                if(kkk[i])
                    ans+=i;
            printf("%d ",ans);
        }
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    if(n<=4000) subtask1::solve();
    return 0;
}

现在我们考虑正解。
对于一个点x来说,它会对哪些点产生作为神仙点的贡献?
如果x和一个点y之间可以仅通过权值小于等于\(a[x]\)的点联通,那么x一定会对点y产生贡献。
如果我们从小到大添加点,那么当添加到x的时候,x会对所有和它联通的点产生贡献。
我们用并查集的方式维护添加建树的过程。
那么每个点到根的路径上的权值和就是它的答案。

对于点权相同的点,我们不能遍历到一个就合并上去,要先记录上贡献,然后再依次合并qwq

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define MAXN 300010
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48); ch=getchar();}
    return x*f;
}
int n,t;
int a[MAXN],h[MAXN],fa[MAXN],head[MAXN];
long long ans[MAXN],val[MAXN];
vector<pair<int,int> >G[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
inline void add(int from,int to)
{
    edge[++t].nxt=head[from],edge[t].to=to;
    head[from]=t;
}
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void dfs(int x,int pre)
{
    ans[x]=ans[pre]+val[x];
    for(int i=head[x];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        dfs(v,x);
    }
}
inline void solve()
{
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read();
        if(a[x]<a[y]) swap(x,y);
        G[a[x]].push_back(make_pair(x,y));
    }
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<G[i].size();j++)
        {
            int x=G[i][j].first;
            int y=G[i][j].second;
            if(a[x]==a[y]) continue;
            if(a[x]<a[y]) swap(x,y);
            val[find(y)]+=x;
        }
        for(int j=0;j<G[i].size();j++)
        {
            int x=G[i][j].first;
            int y=G[i][j].second;
            if(a[x]<a[y]) swap(x,y);
            int xx=find(x),yy=find(y);
            add(xx,yy);
            fa[yy]=xx;
        }
    }
    int root=find(1);
    dfs(root,0);
    for(int i=1;i<=n;i++) printf("%lld ",ans[i]+i);
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    solve();
    return 0;
}

原文地址:https://www.cnblogs.com/fengxunling/p/11127071.html

时间: 2024-10-14 11:40:30

noi.ac #525 神树的权值的相关文章

noi.ac #528 神树和排列

题目链接:戳我 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #include<vector> using namespace std; #define MAXN 8010 #define mod 1000000007 #define ll long long int n,m,a[MAXN],flag[

noi.ac #529 神树的矩阵

题目链接:戳我 当 \(max(n, m) \ge 3\) 时,可以如下构造: 考虑下面这样三个矩阵,红 + 蓝 ? 绿得到的矩阵是一个第一行和最后一行全是 1,其他地方全是 0 的矩阵. 那么如果需要把中间某个位置变成 1,可以在红或蓝矩阵中的对应位置加一个 1. 如果需要把第一行或最后一行某个位置变成 0,可以在绿矩阵中的对应位置加一个 1. (图床挂了......等回来我再放图片QAQ) 然后对于其他情况分别特判就行了(具体哪些可以看main函数) #include<iostream>

AC日记——联合权值 洛谷 P1351

题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu ×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式: 输入文件名为link .in. 第一行包含1 个整数n . 接下来n - 1 行,

NOIp 2014 #2 联合权值 Label:图论 !!!未AC

题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu ×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式: 输入文件名为link .in. 第一行包含1 个整数n . 接下来n - 1 行,

[NOIP2014]联合权值

描述 无向连通图G有n个点,n-1条边.点从1到n依次编号,编号为i的点的权值为Wi  ,每条边的长度均为1.图上两点(u, v)的距离定义为u点到v点的最短距离.对于图G上的点对(u, v),若它们的距离为2,则它们之间会产生Wu×Wv的联合权值. 请问图G上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入格式 输入文件名为link.in. 第一行包含1个整数n. 接下来n-1行,每行包含2个用空格隔开的正整数u.v,表示编号为u和编号为v的点之间有边相连.

洛谷 P1351 联合权值(NOIp2014D1T2)

题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式: 输入文件名为link .in. 第一行包含1 个整数n . 接下来n - 1 行,每

【BZOJ4605】崂山白花蛇草水 权值线段树+kd-tree

[BZOJ4605]崂山白花蛇草水 Description 神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇Aleph的实力,他轻松地进了山东省省队,现在便是他履行诺言的时候了.蒟蒻Bob特地为他准备了999,999,999,999,999,999瓶崂山白花蛇草水,想要灌神犇Aleph.神犇Aleph求(跪着的)蒟蒻Bob不要灌他,由于神犇Aleph是神犇,蒟蒻Bob最终答应了他的请求,但蒟蒻Bob决定将计就计,也让神犇Aleph回答

洛谷1351 联合权值

题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i   ,每条边的长度均为1 .图上两点( u ,  v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式: 输入文件名为link .in. 第一行包含1 个整数n . 接下来n - 1

NOIP 2014 D1T2 -联合权值

联合权值 (link.cpp/c/pas) [问题描述] 无向连通图G有n个点,n-1条边.点从1到n依次编号,编号为i的点的权值为Wi  ,每条边的长度均为1.图上两点(u, v)的距离定义为u点到v点的最短距离.对于图G上的点对(u, v),若它们的距离为2,则它们之间会产生Wu×Wv的联合权值. 请问图G上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? [输入] 输入文件名为link.in. 第一行包含1个整数n. 接下来n-1行,每行包含2个用空格隔开的正