您的位置:首页 > 其它

bzoj 4012: [HNOI2015]开店 (树链剖分+主席树)

2017-04-19 18:40 316 查看

题目描述

传送门

题解

这道题维护和求解的方法和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
,col
,size
,deep
,belong
,p
,q
,son
;
int point
,nxt
,v
,c
,b
,L
,R
,n,m,tot,fa
,pos
,sz,per,cnt,l,r,k;
struct data{
LL val,size,sum,dis;
int ls,rs;
}tr[N*20];
LL dis
;
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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树链剖分 主席树