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;
}