POI2014 Ant colony

Ant colony

POI2014

题意

1.有一棵n个节点的树

2.每个叶子节点有g群蚂蚁进入,第i群有m[i]只

3.每时每刻一个节点最多只有一群蚂蚁

4.当一群蚂蚁要离开度数为d的点时,这群蚂蚁会分成d-1群,每群 ⌊ m d ⌋ \lfloor\frac{m}d \rfloor dm只蚂蚁(向下取整)

5.有一条边上有一只食蚁兽,如果有一群蚂蚁通过这条边,并且数量恰为K只,它就会吞掉这群蚂蚁。

6.问一共有多少只蚂蚁会被吞掉

设食蚁兽在边 (S,T)上
1.从S,T倒退出每个叶子节点最少(和最多)要多少只蚂蚁才能在走到边(S,T)时,被刚好吞噬

2.两遍dfs,一次dfs(S,T),一次dfs(T,S)
dfs(x,f)->当前节点为x,父亲节点为f

3.设到一个点蚂蚁最多可以有mx[x]只,至少要有mi[x]只
mi[x]=mi[f]*(du[x]-1)//刚好均分
mx[x]=mx[f]*(du[x]-1)+max(0,du[x]-2)//余数达到最大

4.然后二分符合条件的有那几群蚂蚁,前缀和计算

具体代码

#include<bits/stdc++.h>
using namespace std;
const int M=1000005;
int n,g,K,len,du[M],cnt[M],A[M];
int head[M],asdf;
long long mi[M],mx[M],ans;
void rd(int &res){
    res=0;
    char c;
    while(c=getchar(),c<48);
    do res=(res<<3)+(res<<1)+(c^48);
    while(c=getchar(),c>47);
}
struct edge {
    int to,nxt;
} G[M*2];
void add_edge(int a,int b) {
    G[++asdf].to=b;
    G[asdf].nxt=head[a];
    head[a]=asdf;
}
void dfs(int x,int f) {
    if(du[x]>1) {
        mi[x]=mi[f]*(du[x]-1);
        mx[x]=mx[f]*(du[x]-1)+max(0,du[x]-2);
    } else {
        mi[x]=mi[f];
        mx[x]=mx[f];
    }
    if(mi[x]>1e9)return;
    if(du[x]==1) {
        int l=upper_bound(A+1,A+1+len,mi[x]-1)-A-1;
        int r=upper_bound(A+1,A+1+len,mx[x])-A-1;
        ans+=1ll*(cnt[r]-cnt[l])*K;
    }
    for(int i=head[x]; i; i=G[i].nxt) {
        int y=G[i].to;
        if(y==f)continue;
        dfs(y,x);
    }
}
int main() {
    int a,b,S,T;
    rd(n),rd(g),rd(K);
    for(int i=1; i<=g; i++)rd(A[i]);
    sort(A+1,A+1+g);
    len=0;
    for(int i=1; i<=g; i++) {
        if(A[i]==A[i-1])cnt[len]++;
        else A[++len]=A[i],cnt[len]=cnt[len-1]+1;
    }
    for(int i=1; i<n; i++) {
        rd(a),rd(b);
        if(i==1)S=a,T=b;
        add_edge(a,b);
        add_edge(b,a);
        du[a]++,du[b]++;
    }
    mi[T]=K,mx[T]=K;
    dfs(S,T);
    mi[S]=K,mx[S]=K;
    dfs(T,S);
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值