题目大意:给定一棵树,选定一棵子树中的一些点,薪水和不能超过m,求点的数量*子树根节点的领导能力的最大值
考虑对于每个节点,我们维护一种数据结构,在其中贪心寻找薪金小的雇佣。
每个节点暴力重建一定不行,我们考虑可并数据结构,每个节点将子节点的信息直接合并即可
可以用启发式合并的Treap,也可以用可并堆
今天特意去学了这玩应0.0 先写了左偏树 然后又写了下随机堆…… 后者速度上更快一些 不过建议从左偏树开始学起
总之平衡树常数各种大就是了0.0
Treap+启发式合并
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 using namespace std; typedef long long ll; struct abcd{ abcd *ls,*rs; int key; int cnt,siz; ll num,sum; abcd (ll x,int y); void Maintain(); }*null=new abcd(0,0),*tree[M]; struct edge{ int to,next; }table[M]; int head[M],tot; int n,root; ll m,ans,leadership[M]; void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } abcd :: abcd(ll x,int y) { ls=rs=null; sum=x*y; num=x; cnt=siz=y; key=y?rand():0; } void abcd :: Maintain() { siz=ls->siz+rs->siz+cnt; sum=ls->sum+rs->sum+num*cnt; } void Zig(abcd *&x) { abcd *y=x->ls; x->ls=y->rs; y->rs=x; x=y; x->rs->Maintain(); } void Zag(abcd *&x) { abcd *y=x->rs; x->rs=y->ls; y->ls=x; x=y; x->ls->Maintain(); } void Insert(abcd *&x,ll y,int z) { if(x==null) { x=new abcd(y,z); return ; } if(y==x->num) x->cnt+=z; else if(y<x->num) { Insert(x->ls,y,z); if(x->ls->key>x->key) Zig(x); } else { Insert(x->rs,y,z); if(x->rs->key>x->key) Zag(x); } x->Maintain(); } int Query(abcd *x,ll y) { if(x==null) return 0; ll temp=x->ls->sum;int re=0; if(y<=temp) return Query(x->ls,y); re+=x->ls->siz;y-=temp; if(y<=x->num*x->cnt) return re+y/x->num; re+=x->cnt;y-=x->num*x->cnt; return re+Query(x->rs,y); } void Decomposition(abcd *&x,int y) { if(x==null) return ; Decomposition(x->ls,y); Decomposition(x->rs,y); Insert(tree[y],x->num,x->cnt); delete x; x=null; } void Tree_DP(int x) { int i; for(i=head[x];i;i=table[i].next) { Tree_DP(table[i].to); if(tree[x]->siz<tree[table[i].to]->siz) swap(tree[x],tree[table[i].to]); Decomposition(tree[table[i].to],x); } ans=max(ans,leadership[x]*Query(tree[x],m)); } int main() { //freopen("2809.in","r",stdin); //freopen("2809.out","w",stdout); int i,fa; ll x; cin>>n>>m; for(i=1;i<=n;i++) { scanf("%d%lld%lld",&fa,&x,&leadership[i]); if(!fa) root=i; else Add(fa,i); tree[i]=new abcd(x,1); } Tree_DP(root); cout<<ans<<endl; } //lld!!
左偏树
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 using namespace std; struct abcd{ abcd *ls,*rs; int num,h; abcd(int x); }*null=new abcd(0),*tree[M]; struct edge{ int to,next; }table[M]; int head[M],tot; int n,m,root,leadership[M],sum[M],size[M]; long long ans; void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } abcd :: abcd(int x) { ls=rs=null; num=x; if(x) h=0; else h=-1; } abcd* Merge(abcd *x,abcd *y) { if(x==null) return y; if(y==null) return x; if(x->num<y->num) swap(x,y); x->rs=Merge(x->rs,y); if(x->ls->h<x->rs->h) swap(x->ls,x->rs); x->h=x->rs->h+1; return x; } void Tree_DP(int x) { int i; for(i=head[x];i;i=table[i].next) { Tree_DP(table[i].to); tree[x]=Merge(tree[x],tree[table[i].to]); sum[x]+=sum[table[i].to]; size[x]+=size[table[i].to]; while(sum[x]>m) { sum[x]-=tree[x]->num; --size[x]; tree[x]=Merge(tree[x]->ls,tree[x]->rs); } } ans=max(ans,(long long)size[x]*leadership[x]); } int main() { int i,fa,x; cin>>n>>m; for(i=1;i<=n;i++) { scanf("%d%d%d",&fa,&x,&leadership[i]); if(!fa) root=i; else Add(fa,i); tree[i]=new abcd(x); sum[i]=x; size[i]=1; } Tree_DP(root); cout<<ans<<endl; }
随机堆
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 using namespace std; struct abcd{ abcd *ls,*rs; int num; abcd(int x); }*null=new abcd(0),*tree[M]; struct edge{ int to,next; }table[M]; bool son; int head[M],tot; int n,m,root,leadership[M],sum[M],size[M]; long long ans; void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } abcd :: abcd(int x) { ls=rs=null; num=x; } abcd* Merge(abcd *x,abcd *y) { if(x==null) return y; if(y==null) return x; if(x->num<y->num) swap(x,y); if(son^=1) x->rs=Merge(x->rs,y); else x->ls=Merge(x->ls,y); return x; } void Tree_DP(int x) { int i; for(i=head[x];i;i=table[i].next) { Tree_DP(table[i].to); tree[x]=Merge(tree[x],tree[table[i].to]); sum[x]+=sum[table[i].to]; size[x]+=size[table[i].to]; while(sum[x]>m) { sum[x]-=tree[x]->num; --size[x]; tree[x]=Merge(tree[x]->ls,tree[x]->rs); } } ans=max(ans,(long long)size[x]*leadership[x]); } int main() { int i,fa,x; cin>>n>>m; for(i=1;i<=n;i++) { scanf("%d%d%d",&fa,&x,&leadership[i]); if(!fa) root=i; else Add(fa,i); tree[i]=new abcd(x); sum[i]=x; size[i]=1; } Tree_DP(root); cout<<ans<<endl; }
时间: 2024-10-08 08:01:08