zoukankan      html  css  js  c++  java
  • 列宁格勒—诺夫哥罗德战役

    特殊数据p=1,当然就把所有点权求和就是答案

    因为是要最小化进攻次数

    考虑到打下面的上面死不了,不妨先把上面的打死

    贪心正确性显然

    然后从上到下,算出当前这个打几下死,把伤害传递下去,这样就有70%的分了(数据造水了)

    1000000的数据,考虑线性解法

    看这个式子Max(0,p-dis(i,j)^2)

    因为j在i的子树内

    所以等价于Max(0,p-(deep[i]-deep[j])^2)

    考虑一个点j受到的来自祖先的伤害

    Hurt=∑(p-(deep[i]-deep[j])^2)((deep[i]-deep[j])^2<p)

    =∑(p-deep[j]^2-deep[i]^2+2*deep[i]*deep[j])((deep[i]-deep[j])^2<p)

    其中,p,deep[j]是已知量,我们在递归时只要记录有效伤害个数,有效伤害深度和,有效伤害深度平方和即可

    理解了解法,具体实现还是很简单的,这里就不在赘述

    难看的代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #define int long long
    #define ll long long
    using namespace std;
    const int maxn=1e6+10;
    struct edge{
        int next,to;
    }e[maxn*2];
    int n,num[maxn],head[maxn],cnt,line[maxn],d[maxn],dis,cnts[maxn],m[maxn];
    ll sum[maxn],sump[maxn],mid;
    inline void add(int x,int y)
    {
        e[++cnt].next=head[x];
        e[cnt].to=y;
        head[x]=cnt;
    }
    void dfs(int x,int pre,int deep)
    {
        d[x]=deep;
        if(d[x]>dis)
        {
            int tmp=d[x]-dis;
            line[x]-=cnts[tmp];
            sum[x]-=(ll)cnts[tmp]*tmp;
            sump[x]-=(ll)cnts[tmp]*tmp*tmp;
        }
        ll all=line[x]*(mid-(ll)d[x]*d[x])-sump[x]+2*d[x]*sum[x];
        if(m[x]>=all)
        {
            num[x]=(m[x]-all)/mid+1;
            cnt+=num[x];
        }
        cnts[d[x]]=num[x];
        for(int v,i=head[x];i;i=e[i].next)
            if((v=e[i].to)!=pre)
            {
                line[v]=line[x]+num[x];
                sum[v]=sum[x]+(ll)num[x]*d[x];
                sump[v]=sump[x]+(ll)num[x]*d[x]*d[x];
                dfs(v,x,deep+1);
            }
    }
    inline void check()
    {
        cnt=0,dis=ceil(sqrt(mid));
        dfs(1,0,1);
    }
    int readn()
    {
        int x=0;
        char c=getchar();
        while(c<'0'||c>'9')
            c=getchar();
        while(c>='0'&&c<='9')
        {
            x=(x<<3)+(x<<1)+(c^'0');
            c=getchar();
        }
        return x;
    }
    signed main()
    {
        n=readn(),mid=readn();
        for(int i=1;i<=n;i++)
            m[i]=readn();
        for(int x,y,i=1;i<n;i++)
        {
            x=readn(),y=readn();
            add(x,y),add(y,x);
        }
        check();
        printf("%lld
    ",cnt);
        return 0;
    }
  • 相关阅读:
    其实 Linux IO 模型没那么难
    七年三次大重构,聊聊我的重构成长史
    听说 JVM 性能优化很难?今天我小试了一把!
    盘点三年来写过的原创文章
    如何快速实现一个连接池?
    树结构系列(四):MongoDb 使用的到底是 B 树,还是 B+ 树?
    树结构系列(三):B树、B+树
    树结构系列(二):平衡二叉树、AVL树、红黑树
    树结构系列(一):从普通树到二叉查找树
    静态代码分析工具清单
  • 原文地址:https://www.cnblogs.com/ivanovcraft/p/9664541.html
Copyright © 2011-2022 走看看