【BZOJ2809】【codevs1763】派遣,主席树记录前缀和

来源:互联网 发布:网络侵犯名誉权案例 编辑:程序博客网 时间:2024/04/28 20:31

传送门1
传送门2
写在前面:祝自己生日快乐
思路:
题意简述为在一棵节点有特征值有费用的有根树上选定一个节点,在它的子树上找任意个节点使其总费用不超过m,要求权值最大(权值=该节点的特征值*选择的节点数)
比较暴力的思路是枚举每一个节点,从它的子树上依次选取费用从小到大的节点,直到超过费用或子树上全部节点都被选了,求出最大值即可,时间复杂度O(n2)
将该思路精进一下,我们发现只要维护每个子树上的点费用从小到大,再加一个前缀和之类的东西,快速判断某一区间费用和是否超过费用即可就可以了
这就用到了主席树
这里的主席树不再是求区间第k大,因为它是权值线段树,节点即是费用(离散化后),所以在主席树上维护下前缀和,每次查询时判断[l,mid]是否超过限制,如果没有就加上左区间的点数,并到[mid+1,r]上去找,不然就继续到[l,mid]上找,每次查询的复杂度为O(nlogn)
注意:
1.维护树上区间使用dfs序重新编号
2.离散化后的值仅是为了在主席树上使其有序,建树和查询时要用到的除了size还有费用前缀和sum
代码:

#include<bits/stdc++.h>#define M 100004#define LL long longusing namespace std;int n,m,cnt,root,tot;LL ans;int fa[M],b[2][M],c[M],ID[M],first[M],Ls[M],Rs[M];//b[0]为离散化前的费用,b[1]为离散化后的费用,ID[i]记录离散化后为i的原费用struct Chairman_tree{    int ch[2],siz;    LL sum;}a[M<<5];struct disc{    int id,data;    bool operator <(const disc other)const    {        return data<other.data;    }}d[M];struct edge{    int u,v,next;    void add(int x,int y)    {        u=x;v=y;        next=first[x];        first[x]=tot;    }}e[M];int in(){    char ch=getchar();int t=0;    while (!isdigit(ch)) ch=getchar();    while (isdigit(ch)) t=(t<<3)+(t<<1)+ch-48,ch=getchar();    return t;}void dfs(int x){    Ls[x]=++cnt;    d[cnt].id=x;d[cnt].data=b[1][x];    for (int i=first[x];i;i=e[i].next)        dfs(e[i].v);    Rs[x]=cnt;}void build(int now,int L,int R,int rt,int val){    a[rt].siz=a[now].siz+1;    a[rt].sum=a[now].sum+ID[val];    if (L==R) return;    int mid=(L+R)>>1;    if (val<=mid)        a[rt].ch[1]=a[now].ch[1],        a[rt].ch[0]=++cnt,        build(a[now].ch[0],L,mid,a[rt].ch[0],val);    else        a[rt].ch[0]=a[now].ch[0],        a[rt].ch[1]=++cnt,        build(a[now].ch[1],mid+1,R,a[rt].ch[1],val);}int get(int begin,int end,int L,int R,LL val){    if (begin==end)        if (ID[end]<=val) return a[R].siz-a[L].siz;        else return 0;    int mid=(begin+end)>>1;    LL t=a[a[R].ch[0]].sum-a[a[L].ch[0]].sum;    if (val>t)        return a[a[R].ch[0]].siz-a[a[L].ch[0]].siz+get(mid+1,end,a[L].ch[1],a[R].ch[1],val-t);    else return get(begin,mid,a[L].ch[0],a[R].ch[0],val);}main(){    n=in();m=in();    for (int i=1;i<=n;i++)    {        fa[i]=in();        if (fa[i]) e[++tot].add(fa[i],i);        else root=i;        b[0][i]=in(),        d[i].id=i,d[i].data=b[0][i];        c[i]=in();    }    sort(d+1,d+n+1);    for (int i=1;i<=n;i++)        b[1][d[i].id]=i,        ID[i]=b[0][d[i].id];    dfs(root);    cnt++;    for (int i=1;i<=n;i++) build(i,1,n,i+1,d[i].data);    for (int i=1;i<=n;i++)        ans=max(ans,(LL)c[i]*get(1,n,Ls[i],Rs[i]+1,m));    printf("%lld",ans);}
0 0