日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 YbtOJ#763-攻城略池【线段树合并】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:http://www.ybtoj.com.cn/problem/763


題目大意

給出nnn個點的一棵樹,每個di=0d_i=0di?=0的點每秒會產生一個士兵往根節點走,走到一個節點讓一個節點did_idi?減一(為000就不管)。

求需要多久才能讓所有點的ddd值變為000

1≤n≤105,1≤di≤1081\leq n\leq10^5,1\leq d_i\leq 10^81n105,1di?108


解題思路

考慮求出每個點did_idi?值變成000的時間tit_iti?

對于一個節點xxxdisxdis_xdisx?表示根節點到xxx的距離,那么它在時刻TTT時的減少數量是
∑y∈subtreexmax{T?ty?disy+disx,0}\sum_{y\in subtree_x}max\{T-t_y-dis_y+dis_x,0\}ysubtreex??max{T?ty??disy?+disx?,0}
我們可以每次把新得到的ty?disyt_y-dis_yty??disy?壓入線段樹,然后每次合并上去后再在線段樹上面二分出答案。

時間復雜度O(nlog?n)O(n\log n)O(nlogn)


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

總結

以上是生活随笔為你收集整理的YbtOJ#763-攻城略池【线段树合并】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。