BZOJ3252: 攻略
题目大意:
一棵有根的有点权的树。
每次可以取某个叶子结点到根的路径的点权和。
并把取过的清0.可以取k次,求取到的最大权值。
题解:
贪心+dfs序+线段树
明显每次取叶子到根的路径权值和最大的,
把叶子节点到根的权值建在线段树上。
每次把路径上节点清0。
假如把p节点清0,在p子树中的叶子节点的sum都会
减去这个节点的值。
sum为根到这个叶子结点的权值和。
代码:
#include<iostream> #include<cstdio> #include<cstring> #define N 200009 #define LL long long using namespace std; int n,k; int sumedge,head[N],b[N]; int cnt,re[N],l[N],r[N],dad[N],vis[N]; LL ans,a[N],w[N]; inline int read(){ char ch=getchar();int x=0,f=1; for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0'; return x*f; } struct Edge{ int x,y,nxt; Edge(int x=0,int y=0,int nxt=0): x(x),y(y),nxt(nxt){} }edge[N]; struct Tree{ int l,r,p; LL mx,s; }tr[N<<2]; void add(int x,int y){ edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } void dfs(int x,LL sum){ bool flag=true;l[x]=cnt+1; for(int i=head[x];i;i=edge[i].nxt){ int v=edge[i].y; if(v==dad[x])continue; dad[v]=x;w[v]+=w[x];flag=false; dfs(v,w[v]); } if(flag)a[++cnt]=sum,re[cnt]=x; r[x]=cnt; } void pushup(int rt){ tr[rt].mx=max(tr[rt<<1].mx,tr[rt<<1|1].mx); tr[rt].p=tr[rt<<1].mx>tr[rt<<1|1].mx?tr[rt<<1].p:tr[rt<<1|1].p; return; } void pushdown(int rt){ if(tr[rt].s==0)return; tr[rt<<1].s+=tr[rt].s;tr[rt<<1|1].s+=tr[rt].s; tr[rt<<1].mx-=tr[rt].s;tr[rt<<1|1].mx-=tr[rt].s; tr[rt].s=0; } void build(int rt,int l,int r){ tr[rt].l=l;tr[rt].r=r; if(l==r){ tr[rt].mx=a[l]; tr[rt].p=l; return; } int mid=(l+r)>>1; build(rt<<1,l,mid);build(rt<<1|1,mid+1,r); pushup(rt); } void change(int rt,int l,int r,int ql,int qr,int p){ if(l>=ql&&r<=qr){ tr[rt].mx-=p; tr[rt].s+=p; return; } pushdown(rt); int mid=(l+r)>>1; if(ql<=mid)change(rt<<1,l,mid,ql,qr,p); if(qr>mid)change(rt<<1|1,mid+1,r,ql,qr,p); pushup(rt); } int main(){ n=read();k=read(); for(int i=1;i<=n;i++)w[i]=read(),b[i]=w[i]; for(int i=1;i<n;i++){ int x,y; x=read();y=read(); add(x,y); } dfs(1,w[1]); build(1,1,cnt); for(int i=1;i<=k;i++){ LL t=tr[1].mx;int p=tr[1].p; if(t<=0)break;ans+=t; p=re[p]; while(p&&vis[p]==0){ vis[p]=true; change(1,1,cnt,l[p],r[p],b[p]); p=dad[p]; } } printf("%lld\n",ans); return 0; }