HDU - 5788 主席树+树状数组
老早之前写的题了,最近弄项目的空余,顺便补补题。
题意:所有人的关系是一棵树,1是老板,也就是根节点,然后每个人都有个权值ai,每个人所领的万恶的资本主义的工资就是他所在子树的所有人能力值的中位数。你可以更改其中一个人的能力值为1e5,问所有人工资的和最大是多少?
思路:当我们更改某个人u的能力值时,只会对u到根节点的这一条链上的节点会有影响,而这个影响更详细点就是,这条链上某个中位数小于等于u的能力值的节点v,它的中位数便会往后移动一位。
那么我们便先用主席树获取每个节点的中位数以及中位数的下一个数(注意叶子节点中位数位本身,中位数下一个数应该为1e5),然后dfs遍历枚举每一个点能力值修改的情况,用树状数组维护相应能获得的权值,更新其中最大值即可。
//当一个数的权值,小于等于它祖先的中位数时,对其进行修改则会让受到影响的祖先中位数变成原来的中位数的下一个 //每个点的中位数和下一个可以由主席树求得,然后树状数组维护一条链上的修改情况,遍历每个点求更新能获得的最大变动值 #include<bits/stdc++.h> #define lowb(x) (x&(-x)) using namespace std; typedef long long ll; const int N=1e5+11; struct Tree{ int lson,rson,sum; }T[N*32]; struct Side{ int v,ne; }S[N]; int sn,head[N]; int dn,did[N],size[N]; int tn,a[N],root[N]; int val1[N],val2[N]; ll res,sum[N]; void init(){ sn=dn=tn=0; memset(sum,0,sizeof(sum)); memset(head,-1,sizeof(head)); } void addS(int u,int v){ S[sn].v=v; S[sn].ne=head[u]; head[u]=sn++; } int build(int l,int r){ int cur=++tn,mid=(l+r)>>1; T[cur].sum=0; if(l==r) return cur; T[cur].lson=build(l,mid); T[cur].rson=build(mid+1,r); return cur; } int addT(int x,int l,int r,int p){ int cur=++tn,mid=(l+r)>>1; T[cur]=T[x]; T[cur].sum++; if(l==r) return cur; if(p<=mid) T[cur].lson=addT(T[x].lson,l,mid,p); else T[cur].rson=addT(T[x].rson,mid+1,r,p); return cur; } int query(int L,int R,int l,int r,int p){ if(l==r) return l; int mid=(l+r)>>1; int lsum=T[T[R].lson].sum-T[T[L].lson].sum; if(lsum>=p) return query(T[L].lson,T[R].lson,l,mid,p); return query(T[L].rson,T[R].rson,mid+1,r,p-lsum); } void updata(int x,int val){ while(x){ sum[x]+=val; x-=lowb(x); } } ll query2(int x){ ll ans=0; while(x<N){ ans+=sum[x]; x+=lowb(x); } return ans; } void dfs(int u){ did[u]=++dn; root[dn]=addT(root[dn-1],1,100000,a[u]); size[u]=1; for(int i=head[u];~i;i=S[i].ne){ int v=S[i].v; dfs(v); size[u]+=size[v]; } } void dfs2(int u){ updata(val1[u],val2[u]); res=max(res,query2(a[u])); for(int i=head[u];~i;i=S[i].ne){ int v=S[i].v; dfs2(v); } updata(val1[u],-val2[u]); } int main(){ int n,fa; while(~scanf("%d",&n)){ init(); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=2;i<=n;i++){ scanf("%d",&fa); addS(fa,i); } root[0]=build(1,100000); dfs(1); ll ans=0; for(int i=1;i<=n;i++){ if(size[i]==1){ val1[i]=a[i]; val2[i]=100000-a[i]; ans+=a[i]; }else{ int l=did[i],r=did[i]+size[i]-1; int pos=(r-l+2)>>1; // printf("%d %d %d\n",l,r,pos); val1[i]=query(root[l-1],root[r],1,100000,pos); val2[i]=query(root[l-1],root[r],1,100000,pos+1)-val1[i]; ans+=val1[i]; } // printf("%d %d\n",val1[i],val2[i]); } res=0; dfs2(1); // printf("%lld %lld\n",res,ans); printf("%lld\n",ans+res); } return 0; }
我太难了~给个三连吧,亲~~~