YbtOJ#763-攻城略池【线段树合并】

正题

题目链接:http://www.ybtoj.com.cn/problem/763


题目大意

给出\(n\)个点的一棵树,每个\(d_i=0\)的点每秒会产生一个士兵往根节点走,走到一个节点让一个节点\(d_i\)减一(为\(0\)就不管)。

求需要多久才能让所有点的\(d\)值变为\(0\)

\(1\leq n\leq10^5,1\leq d_i\leq 10^8\)


解题思路

考虑求出每个点\(d_i\)值变成\(0\)的时间\(t_i\)

对于一个节点\(x\)\(dis_x\)表示根节点到\(x\)的距离,那么它在时刻\(T\)时的减少数量是

\[\sum_{y\in subtree_x}max\{T-t_y-dis_y+dis_x,0\} \]

我们可以每次把新得到的\(t_y-dis_y\)压入线段树,然后每次合并上去后再在线段树上面二分出答案。

时间复杂度\(O(n\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e5+10,inf=2e8;
struct node{
	ll to,next,w;
}a[N<<1];
ll n,tot,cnt,ans,ls[N],d[N],t[N],rt[N],dep[N];
void addl(ll x,ll y,ll w){
	a[++tot].to=y;
	a[tot].next=ls[x];
	ls[x]=tot;a[tot].w=w;
	return;
}
struct SegTree{
	ll w[N<<6],c[N<<6],ls[N<<6],rs[N<<6];
	void Change(ll &x,ll L,ll R,ll pos){
		if(!x)x=++cnt;w[x]+=pos;c[x]++;
		if(L==R)return;ll mid=(L+R)>>1;
		if(pos<=mid)Change(ls[x],L,mid,pos);
		else Change(rs[x],mid+1,R,pos);
		return;
	}
	ll Ask(ll x,ll L,ll R,ll k,ll zc,ll zw){
		if(L==R)return L;
		ll mid=(L+R)>>1,tmp=mid*(c[ls[x]]+zc)-w[ls[x]]-zw;
		if(tmp>=k)return Ask(ls[x],L,mid,k,zc,zw);
		return Ask(rs[x],mid+1,R,k,zc+c[ls[x]],zw+w[ls[x]]);
	}
	ll Merge(ll x,ll y,ll l,ll r){
		if(!x||!y)return x+y;
		w[x]=w[x]+w[y];c[x]=c[x]+c[y];
		if(l==r)return x;ll mid=(l+r)>>1;
		ls[x]=Merge(ls[x],ls[y],l,mid);
		rs[x]=Merge(rs[x],rs[y],mid+1,r);
		return x;
	}
}T;
void dfs(ll x,ll fa){
	for(ll i=ls[x];i;i=a[i].next){
		ll y=a[i].to;
		if(y==fa)continue;
		dep[y]=dep[x]+a[i].w;dfs(y,x);
		rt[x]=T.Merge(rt[x],rt[y],0,inf);
	}
	t[x]=max(0ll,T.Ask(rt[x],0,inf,d[x],0,0)-dep[x]);
	T.Change(rt[x],0,inf,t[x]+dep[x]);
	ans=max(ans,t[x]);return;
}
signed main()
{
//	freopen("conquer.in","r",stdin);
//	freopen("conquer.out","w",stdout);
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++)
		scanf("%lld",&d[i]);
	for(ll i=1;i<n;i++){
		ll x,y,w;
		scanf("%lld%lld%lld",&x,&y,&w);
		addl(x,y,w);addl(y,x,w);
	}
	dfs(1,1);
	printf("%lld\n",ans);
	return 0;
}
posted @ 2021-02-21 15:00  QuantAsk  阅读(59)  评论(0编辑  收藏  举报