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\n", Ans*k);
    return 0;
}

 

posted @ 2018-10-20 11:53  薄荷凉了夏  阅读(123)  评论(0编辑  收藏  举报