BZOJ 4458: GTY的OJ【主席树+LCA+堆】

4458: GTY的OJ

【题目描述】
传送门

【题解】

其实就是在树上做超级钢琴,用主席树维护这棵树,那么影响到这个节点x的状态只有fa[x],那么主席树就根据fa[x]转移到x,很好想,边界的判断要注意一下。
主席树维护树上前缀和的值,然后用堆取前m个最大的就可以了。

代码如下

#include<cstdio>
#include<cctype>
#include<algorithm>
#define LL long long
#define MAXN 500005
using namespace std;
int n,m,Top,Root,SNumber=1e9,BNumber=-1e9,a[MAXN],Fa[MAXN],Dep[MAXN];
int tot,T[MAXN],Tre[MAXN*30],L[MAXN*30],R[MAXN*30];
int F[MAXN][30];LL Ans;
struct HEAP{
    int x,id,t;
    bool operator <(const HEAP b)const{return x<b.x;}
}hep[MAXN];
struct Edge{
    int tot,lnk[MAXN],nxt[MAXN],son[MAXN];
    void Add(int x,int y){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;}
}E;
void put(HEAP x){
    hep[++Top]=x;
    push_heap(hep+1,hep+1+Top);
}
HEAP get(){
    pop_heap(hep+1,hep+1+Top);
    return hep[Top--];
}
int read(){
    int ret=0;char ch=getchar();bool f=1;
    for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
    for(; isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-48;
    return f?ret:-ret;
}
void DFS(int x,int fa){
    a[x]+=a[fa];Fa[x]=fa;Dep[x]=Dep[fa]+1;
    for(int j=E.lnk[x];j;j=E.nxt[j])
    if(E.son[j]!=fa) DFS(E.son[j],x);
}
int Updata(int lst,int l,int r,int p){
    int rt=++tot;
    Tre[rt]=Tre[lst]+1;L[rt]=L[lst],R[rt]=R[lst];
    if(l<r){
        int mid=(r+l)>>1;
        if(p<=mid) L[rt]=Updata(L[lst],l,mid,p);
        else R[rt]=Updata(R[lst],mid+1,r,p);
    }
    return rt;
}
int Query(int u,int v,int l,int r,int p){
    if(l>=r) return l;
    int mid=(l+r)>>1,Now=Tre[L[v]]-Tre[L[u]];
    if(p<=Now) return Query(L[u],L[v],l,mid,p);
    else return Query(R[u],R[v],mid+1,r,p-Now);
}
void LCA(){
    for(int i=1;i<=n;i++){
        F[i][0]=Fa[i];
        for(int j=1;(1<<j)<n;j++) F[i][j]=-1;   
    }
    for(int j=1;(1<<j)<n;j++)
    for(int i=1;i<=n;i++)
    if(F[i][j-1]!=-1) F[i][j]=F[F[i][j-1]][j-1];
}
int GetF(int x,int l){
    int LOG=0,D=Dep[x]-l;
    if(D<0) return 0;
    for(LOG=1;(1<<LOG)<=Dep[x];LOG++);LOG--; 
    for(int i=LOG;i+1;i--)
    if(Dep[x]-(1<<i)>=D) x=F[x][i];
    return x;
}
int main(){
    n=read()+1;Root=1;
    for(int i=2;i<=n;i++){int x=read()+1;E.Add(x,i);}
    for(int i=2;i<=n;i++) a[i]=read();
    DFS(Root,0);
    for(int i=1;i<=n;i++) BNumber=max(BNumber,a[i]),SNumber=min(SNumber,a[i]);
    BNumber++;SNumber--;
    for(int i=1;i<=n;i++) T[i]=Updata(T[Fa[i]],SNumber,BNumber,a[i]);
    m=read();int l=read(),r=read();LCA();
    for(int i=1;i<=n;i++){
        int ll=GetF(i,l),rr=GetF(i,r);
        if(ll<=0) continue;
        if(rr<=0) rr=1;
//      printf("i=%d l=%d r=%d %d\n",i,Fa[rr],ll,Query(T[Fa[rr]],T[ll],SNumber,BNumber,1));
        put((HEAP){a[i]-Query(T[Fa[rr]],T[ll],SNumber,BNumber,1),i,1});
    }
    for(int i=1;i<=m;i++){
        if(Top==0) continue;
        HEAP Now=get();
        Ans+=Now.x;
        int ll=GetF(Now.id,l),rr=GetF(Now.id,r);
        if(ll<=0) continue;
        if(rr<=0) rr=1;
        int Nxt=Query(T[Fa[rr]],T[ll],SNumber,BNumber,Now.t+1);
        if(Nxt==BNumber) continue;
        put((HEAP){a[Now.id]-Nxt,Now.id,Now.t+1});
    }
    printf("%lld\n",Ans);
    return 0;
}
posted @ 2018-07-06 15:04  XSamsara  阅读(89)  评论(0编辑  收藏  举报