zoukankan      html  css  js  c++  java
  • BZOJ 3872 ant colony


    一道比较有意思的好题目吧。

    这道题其实思路应该是很有意思的。

    我们注意到,这棵树被一条关键的边分成了两部分。
    当从两边来的数量恰好是要求的数量时,才会计算答案。
    那么我们考虑到题目中,传递信息的方式是固定的,
    也就是说,我们只要确定了叶节点就能够算出答案。
    那么n方暴力就很显然了:枚举每一个叶节点,遍历树计算答案。

    考虑优化。
    其实上述算法对与 传递信息方式固定 这一性质没有很好的利用上。
    这个东西它可以意味着什么呢。
    我们考虑一下如果经过关键边时为x计算答案,
    那么所有与两个端点相连的边
    也只有在当经过它时,数量在一定区间范围内才能贡献答案,这样就直接逆向利用信息传递就可求。
    同理,推广到所有边。
    这样最后每一个叶节点都会有一个区间,仅仅只有在这个区间内才能贡献答案。
    那么二分查找一下就好了。时间复杂度O(nlogn)。写的时候注意点细节(区间的开闭)等。。

    #include <bits/stdc++.h>
    using namespace std;
    inline int gi () {
        int x=0, w=0; char ch=0;
        while (! (ch>='0' && ch<='9') ) {
            if (ch=='-') w=1;
            ch=getchar ();
        }
        while (ch>='0' && ch<='9') {
            x= (x<<3) + (x<<1) + (ch^48);
            ch=getchar ();
        }
        return w?-x:x;
    }
    
    const int G=1e6+10;
    int n,g,tot,KeyEdx,KeyEdy,head[G];
    long long k,Ran[G][2],Ant[G],Ind[G],Ans;
    
    struct Tree {
        int next, now;
    }t[G<<1];
    inline void make (int from, int to) {
        t[++tot].next=head[from];
        head[from]=tot;
        t[tot].now=to;
    }
    
    void DFS (int x, int fax) {
        for (int i=head[x];i;i=t[i].next) {
            int Nex=t[i].now;
            if (Nex==fax) continue;
            if (Ind[Nex]==1) {
                Ran[Nex][0]=Ran[x][0],
                Ran[Nex][1]=Ran[x][1];
            }
            else {
                Ran[Nex][0]=Ran[x][0]* (Ind[Nex]-1); 
                Ran[Nex][1]=Ran[x][1]* (Ind[Nex]-1)+Ind[Nex]-2;
            }    
            DFS (Nex, x);
        }
    }
    
    int main ()
    {
        n=gi (), g=gi (), k=gi ();
        for (int i=1;i<=g;++i) Ant[i]=gi ();
        sort (Ant+1, Ant+g+1);
        for (int i=1, x, y;i<n;++i) {
            x=gi (), y=gi ();
            Ind[x]++, Ind[y]++;
            make (x, y), make (y, x);
            if (i==1) {
                KeyEdx=x;
                KeyEdy=y;
            }
        }
        if (Ind[KeyEdx]==1) Ran[KeyEdx][0]=Ran[KeyEdx][1]=k;
        else  {
             Ran[KeyEdx][0]=k* (Ind[KeyEdx]-1);
             Ran[KeyEdx][1]=Ran[KeyEdx][0]+Ind[KeyEdx]-2;
        }
        if (Ind[KeyEdy]==1) Ran[KeyEdy][0]=Ran[KeyEdy][1]=k;
        else  {
             Ran[KeyEdy][0]=k* (Ind[KeyEdy]-1);
             Ran[KeyEdy][1]=Ran[KeyEdy][0]+Ind[KeyEdy]-2;
        }
        DFS (KeyEdx, KeyEdy);
        DFS (KeyEdy, KeyEdx);
        for (int i=1;i<=n;++i) {
            if (Ind[i]>1) continue;
            Ans+=upper_bound (Ant+1, Ant+g+1, Ran[i][1])-lower_bound (Ant+1, Ant+g+1, Ran[i][0]);
        }
        printf ("%lld
    ", Ans*k);
        return 0;
    }
  • 相关阅读:
    nginx 开机自动启动
    Linux 常用命令
    php中数组操作函数
    Windows系统下GitBash显示的中文乱码解决方案
    更改Git默认编辑器为notepad++
    【js】函数问题
    【JS】JavaScript中的参数传递
    Android基础整理之四大组件Activity
    关于BaseAdapter的使用及优化心得(一)
    使用MySQL Workbench建立数据库,建立新的表,向表中添加数据
  • 原文地址:https://www.cnblogs.com/Bhllx/p/9821142.html
Copyright © 2011-2022 走看看