codeforces 1100F

传送门:http://codeforces.com/contest/1099/problem/F

题意:

两个人在玩游戏。

第一个人从根结点出发。

每次可以选择往下走一个结点或者结束游戏返回根结点并选择性的吃结点上的饼干。

第二个人在第一个人每次向下走之后可以选择一个当前节点的儿子节点ban掉。

第一个人一定要在规定时间内返回到根结点,问最多能吃多少块饼干。

题解:

假设我们在t结点结束游戏,那么能吃饼干的时间就是总时间T减去在边上花费的时间,能吃的饼干数可以用时间作为线段树下标保存并查询,考虑到第二个人也是最优策略,所以我们在非根结点往下走肯定是只能走次优的结点,即答案只能加上第二大的节点贡献。

#include
using namespace std;
typedef long long ll;
const int maxn=100005;
ll x[maxn],c[maxn],sum[(maxn*10)<<2],num[(maxn*10)<<2],ans[maxn],ansm[maxn][2];
struct node{
	int to,nex;
	ll val;
}edge[maxn<<1];
int head[maxn],cnt;
void add(int u,int v,ll w){
	edge[cnt].to=v;
	edge[cnt].nex=head[u];
	edge[cnt].val=w;
	head[u]=cnt++;
}
void update(int t,int l,int r,ll pos,ll nu){
	sum[t]+=pos*nu;
	num[t]+=nu;
	if(l==r)return ;
	int mid=l+r>>1;
	if(pos<=mid)update(t<<1,l,mid,pos,nu);
	else update(t<<1|1,mid+1,r,pos,nu);
}
ll query(int t,int l,int r,ll tim){
	if(sum[t]<=tim)return num[t];
	if(l==r)return tim/l;
	int mid=l+r>>1;
	if(sum[t<<1]ansm[t][0])swap(anss,ansm[t][0]);
		if(anss>ansm[t][1])swap(anss,ansm[t][1]);
	}
	if(t==1)ans[t]=max(ans[t],ansm[t][0]);
	else ans[t]=max(ans[t],ansm[t][1]);
	update(1,1,1000000,c[t],-x[t]);
}
int main(){
	ll t;
	int n;
	scanf("%d%lld",&n,&t);
	for(int i=1;i<=n;i++){
		scanf("%lld",&x[i]);
	}
	for(int i=1;i<=n;i++){
		scanf("%lld",&c[i]);
	}
	memset(head,-1,sizeof(head));
	for(int i=2;i<=n;i++){
		int p;
		ll l;
		scanf("%d%lld",&p,&l);
		add(p,i,l);
	}
	dfs(1,t);
	printf("%lld\n",ans[1]);
	return 0;
}

 

你可能感兴趣的:(dfs,线段树)