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

题目描述

传送门

题解

这道题维护和求解的方法和bzoj 3924: [Zjoi2015]幻想乡战略游戏是类似的。
但是这道题有一个[L,R]的区间限制,所以我们用主席树来维护,外层是按照离散化后的 xi 从小到大,内层是dfs序。

代码

#include
#include
#include
#include
#include
#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]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 (itr[++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 (itr[++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]]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]]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;iint 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 (r1,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);
    }
}

你可能感兴趣的:(树链剖分,主席树)