1. 程式人生 > >bzoj 4012: [HNOI2015]開店 (樹鏈剖分+主席樹)

bzoj 4012: [HNOI2015]開店 (樹鏈剖分+主席樹)

題目描述

傳送門

題解

這道題維護和求解的方法和bzoj 3924: [Zjoi2015]幻想鄉戰略遊戲是類似的。
但是這道題有一個[L,R]的區間限制,所以我們用主席樹來維護,外層是按照離散化後的xi從小到大,內層是dfs序。

程式碼

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define N 300010
#define LL long long 
using namespace std;
int
root[N],col[N],size[N],deep[N],belong[N],p[N],q[N],son[N]; int point[N],nxt[N],v[N],c[N],b[N],L[N],R[N],n,m,tot,fa[N],pos[N],sz,per,cnt,l,r,k; struct data{ LL val,size,sum,dis; int ls,rs; }tr[N*20]; LL dis[N]; int cmp(int x,int y) { return col[x]<col[y]; } void add(int x,int y,int z) { tot++; nxt[tot]=point[x
]; point[x]=tot; v[tot]=y; c[tot]=z; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; c[tot]=z; } void dfs(int x,int f) { deep[x]=deep[f]+1; size[x]=1; for (int i=point[x];i;i=nxt[i]){ if(v[i]==f) continue; dis[v[i]]=(LL)dis[x]+c[i]; fa[v[i]]=x; dfs(v[i],x
); size[x]+=size[v[i]]; if (size[v[i]]>size[son[x]]) son[x]=v[i]; } } void dfs1(int x,int chain) { pos[x]=++sz; belong[x]=chain; p[sz]=x; L[x]=R[x]=sz; if (!son[x]) return; dfs1(son[x],chain); for (int i=point[x];i;i=nxt[i]) if (v[i]!=son[x]&&v[i]!=fa[x]) dfs1(v[i],v[i]); R[x]=sz; } void update(int now) { int l=tr[now].ls; int r=tr[now].rs; tr[now].size=tr[l].size+tr[r].size; tr[now].val=tr[l].val+tr[r].val; tr[now].sum=tr[l].sum+tr[r].sum; } void addsize(int &i,int l,int r,int x) { if (i<root[per]) { tr[++sz]=tr[i]; i=sz; } if (l==r) { tr[i].size+=1; tr[i].val+=dis[p[l]]; tr[i].sum+=dis[p[l]]; return; } int mid=(l+r)/2; if (x<=mid) addsize(tr[i].ls,l,mid,x); else addsize(tr[i].rs,mid+1,r,x); update(i); } void pointchange(int &i,int l,int r,int x,LL val) { if (i<root[per]) { tr[++sz]=tr[i]; i=sz; } if (l==r) { tr[i].sum+=val; return; } int mid=(l+r)/2; if (x<=mid) pointchange(tr[i].ls,l,mid,x,val); else pointchange(tr[i].rs,mid+1,r,x,val); update(i); } void solve(int x,int y) { while (belong[x]!=belong[y]) { if (deep[belong[x]]<deep[belong[y]]) swap(x,y); int t=fa[belong[x]]; pointchange(root[per],1,n,pos[t],dis[t]); x=fa[belong[x]]; } } LL qjsum(int i,int j,int l,int r,int ll,int rr,int opt) { if (ll>rr) return 0; if (ll<=l&&r<=rr) { if (opt==1) return tr[j].size-tr[i].size; else return tr[j].sum-tr[i].sum; } int mid=(l+r)/2; LL ans=0; if (ll<=mid) ans+=qjsum(tr[i].ls,tr[j].ls,l,mid,ll,rr,opt); if (rr>mid) ans+=qjsum(tr[i].rs,tr[j].rs,mid+1,r,ll,rr,opt); return ans; } LL calc(int x,int y) { if (x==y) return 0; LL ans=0; while (belong[x]!=belong[y]) { if (deep[belong[x]]<deep[belong[y]]) swap(x,y); ans+=qjsum(root[l-1],root[r],1,n,pos[belong[x]],pos[fa[x]],0); x=belong[x]; LL t=qjsum(root[l-1],root[r],1,n,L[fa[x]],R[fa[x]],1)-qjsum(root[l-1],root[r],1,n,L[x],R[x],1); ans+=t*dis[fa[x]]; x=fa[x]; } if (pos[x]>pos[y]) swap(x,y); ans+=qjsum(root[l-1],root[r],1,n,pos[x],pos[fa[y]],0); return ans; } int main() { freopen("shop_hnoi2015.in","r",stdin); freopen("shop_hnoi2015.out","w",stdout); scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=n;i++) scanf("%d",&col[i]),b[i]=col[i]; sort(b+1,b+n+1); cnt=unique(b+1,b+n+1)-b-1; for (int i=1;i<=n;i++) col[i]=lower_bound(b+1,b+cnt+1,col[i])-b,q[i]=i; sort(q+1,q+n+1,cmp); for (int i=1;i<n;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); } dfs(1,0); dfs1(1,1); int now=1; sz=0; for (int i=1;i<=cnt;i++) { root[i]=++sz; per=i; tr[sz]=tr[root[i-1]]; while (col[q[now]]==i&&now<=n) { addsize(root[i],1,n,pos[q[now]]); solve(1,q[now]); now++; } } LL ans=0; for (int i=1;i<=m;i++) { int u; int a1,b1; scanf("%d%d%d",&u,&a1,&b1); if (i==1) l=min(a1%k,b1%k),r=max(a1%k,b1%k); else l=min((LL)(a1+ans)%k,(LL)(b1+ans)%k),r=max((LL)(a1+ans)%k,(LL)(b1+ans)%k); l=lower_bound(b+1,b+cnt+1,l)-b; if (r<b[cnt]) r=lower_bound(b+1,b+cnt+1,r+1)-b,r--; else r=cnt; ans=0; ans+=tr[root[r]].val-tr[root[l-1]].val; ans+=(tr[root[r]].size-tr[root[l-1]].size)*dis[u]; ans-=(LL)qjsum(root[l-1],root[r],1,n,L[u],R[u],1)*dis[u]*2; ans-=(LL)calc(1,u)*2; printf("%lld\n",ans); } }