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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

jzoj4050-寻宝游戏【二分,树状数组,LCA】

發布時間:2023/12/3 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jzoj4050-寻宝游戏【二分,树状数组,LCA】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://jzoj.net/senior/#contest/show/3017/1


題目大意

nnn個點的一棵樹,mmm次操作,修改一個地方的寶藏。

每次操作后求拿完所以寶藏并回到原地的最小距離。


解題思路

顯然起點在任何一個有寶藏的地方都是最優的,而且順著dfsdfsdfs序走是最優的。

所以對于每次加入的寶藏,我們用二分+樹狀數組找出兩邊dfsdfsdfs序最近的然后用LCALCALCA對距離進行計算即可。

時間復雜度O(nlog?2n)O(n\log^2 n)O(nlog2n)


codecodecode

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long #define lowbit(x) (x&-x) using namespace std; const ll N=2e5+10,T=18; struct node{ll to,next,w; }a[N*2]; ll tot,ls[N],f[N][T]; ll dfn[N],rfn[N],dep[N],dis[N],cnt; ll n,m,ans; bool v[N]; struct Tree_Array{ll t[N];void Change(ll x,ll val){while(x<=2*n){t[x]+=val;x+=lowbit(x);}return;}ll Ask(ll x){ll ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;}ll Query(ll l,ll r){return Ask(r)-Ask(l-1);}ll Get_Pre(ll x){ll l=1,r=n;if(Ask(x)==0)return 0;while(l<=r){ll mid=(l+r)>>1;if(Query(max(x-mid,1ll),x)>0) r=mid-1;else l=mid+1;}return max(x-l,1ll);}ll Get_Aft(ll x){ll l=1,r=n;if(Ask(n*2)-Ask(x)==0)return 0;while(l<=r){ll mid=(l+r)>>1;if(Query(x,min(x+mid,n*2))>0) r=mid-1;else l=mid+1;}return min(x+l,n*2);} }TA; void addl(ll x,ll y,ll w){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w; } void dfs(ll x,ll fa){dfn[++cnt]=x;rfn[x]=cnt;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa) continue;f[y][0]=x;dep[y]=dep[x]+1;dis[y]=dis[x]+a[i].w;dfs(y,x);}return; } ll pref(ll x){ll z;if(z=TA.Get_Pre(rfn[x])) return dfn[z];return dfn[TA.Get_Pre(rfn[x]+n)]; } ll aftf(ll x){ll z;if(z=TA.Get_Aft(rfn[x]+n)) return dfn[z];return dfn[TA.Get_Aft(rfn[x])]; } ll LCA(ll x,ll y){if(dep[x]>dep[y]) swap(x,y);for(ll i=T-1;i>=0;i--)if(dep[f[y][i]]>=dep[x])y=f[y][i];if(x==y) return y;for(ll i=T-1;i>=0;i--)if(f[y][i]!=f[x][i])x=f[x][i],y=f[y][i];return f[x][0]; } ll get_dis(ll x,ll y) {return dis[x]+dis[y]-2*dis[LCA(x,y)];} int main() {scanf("%lld%lld",&n,&m);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);}dep[0]=-1;dfs(1,0);for(ll i=1;i<=n;i++)dfn[i+n]=dfn[i]; for(ll i=1;i<T;i++)for(ll j=1;j<=n;j++)f[j][i]=f[f[j][i-1]][i-1];ll w=0;while(m--){ll x;scanf("%lld",&x);if(v[x]){v[x]=0;w--;TA.Change(rfn[x],-1);TA.Change(rfn[x]+n,-1);if(w){ll l=pref(x),r=aftf(x);ans=ans-get_dis(l,x)-get_dis(x,r)+get_dis(l,r); }}else{if(w){ll l=pref(x),r=aftf(x);ans=ans+get_dis(l,x)+get_dis(x,r)-get_dis(l,r); }v[x]=1;w++;TA.Change(rfn[x],1);TA.Change(rfn[x]+n,1);}printf("%lld\n",ans);} }

總結

以上是生活随笔為你收集整理的jzoj4050-寻宝游戏【二分,树状数组,LCA】的全部內容,希望文章能夠幫你解決所遇到的問題。

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