洛谷 P1552 [APIO2012]派遣(左偏树,贪心)
传送门
解题思路
比较难想到用左偏树。
因为管理者的图是个DAG,再加上满意度只与数量与管理者的领导力有关(这样贪心选薪水最低的),所以可以用左偏树合并+不断删最大值来保证总薪水小于总预算。
左偏树结构体里除了平常的东西还要加上总薪水、总人数。
具体做法就是先建树,然后dfs一遍,回溯的时候合并+删除+更新ans。
AC代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn=100005; 6 int n,m,b[maxn],c[maxn],p[maxn],cnt,fa[maxn]; 7 long long ans,l[maxn]; 8 struct node1{ 9 int v,next; 10 }e[maxn]; 11 struct node2{ 12 int rs,ls,dis,num; 13 long long value; 14 }t[maxn]; 15 void insert(int u,int v){ 16 cnt++; 17 e[cnt].v=v; 18 e[cnt].next=p[u]; 19 p[u]=cnt; 20 } 21 int find(int x){ 22 return fa[x]==x?x:fa[x]=find(fa[x]); 23 } 24 void update(int x){ 25 if(t[t[x].rs].dis>t[t[x].ls].dis) swap(t[x].rs,t[x].ls); 26 int rs=t[x].rs,ls=t[x].ls; 27 t[x].value=t[rs].value+t[ls].value+c[x]; 28 t[x].num=t[rs].num+t[ls].num+1; 29 t[x].dis=t[rs].dis+1; 30 } 31 int merge(int x,int y){ 32 if(!x||!y) return x|y; 33 if(x==y) return x; 34 if(c[x]<c[y]) swap(x,y); 35 t[x].rs=merge(t[x].rs,y); 36 fa[t[x].rs]=x; 37 update(x); 38 return x; 39 } 40 int goout(int x){ 41 fa[t[x].rs]=t[x].rs; 42 fa[t[x].ls]=t[x].ls; 43 int newtop=merge(t[x].rs,t[x].ls); 44 fa[x]=newtop; 45 return newtop; 46 } 47 void dfs(int u){ 48 for(int i=p[u];i!=-1;i=e[i].next){ 49 dfs(e[i].v); 50 int newtop=merge(find(e[i].v),find(u)); 51 while(t[newtop].value>m){ 52 newtop=goout(newtop); 53 } 54 } 55 int newroot=find(u); 56 ans=max(ans,l[u]*t[newroot].num); 57 } 58 int main(){ 59 memset(p,-1,sizeof(p)); 60 cin>>n>>m; 61 for(int i=1;i<=n;i++) scanf("%d%d%d",&b[i],&c[i],&l[i]); 62 for(int i=1;i<=n;i++){ 63 fa[i]=i; 64 t[i].num=1; 65 t[i].value=c[i]; 66 } 67 for(int i=2;i<=n;i++){ 68 insert(b[i],i); 69 } 70 dfs(1); 71 cout<<ans; 72 return 0; 73 }
//APIO 2012 t1