BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]

传送门

题意:查询树上根节点值*子树中权值和$\le m$的最大数量 最大值是多少



求$DFS$序,然后变成区间中和$\le m$最多有几个元素,建主席树,然后权值线段树上二分就行了

$WA$:又把边表开小了.....

好吧我$zz$了有根树加无向边干什么....

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lc(x) t[x].l
#define rc(x) t[x].r
typedef long long ll;
const int N=1e5+5;
int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();}
    return x*f;
}
int n,m,mp[N];
struct Ninjia{
    int w,li,id;
    bool operator <(const Ninjia &r)const{return w<r.w;}
}a[N];
inline bool cmpId(Ninjia a,Ninjia b){return a.id<b.id;}
struct Edge{
    int v,ne;
}e[N<<1];
int h[N],cnt;
inline void ins(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt;
}
int L[N],R[N],dfc,pos[N];
void dfs(int u,int fa){
    L[u]=++dfc; pos[dfc]=u;
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].v!=fa) dfs(e[i].v,u);
    R[u]=dfc;
}

struct Node{
    int l,r,size;
    ll sum;
}t[N*30];
int sz,root[N];
void fIns(int &x,int l,int r,int p){
    t[++sz]=t[x];x=sz;
    t[x].size++;
    t[x].sum+=(ll)mp[p];
    if(l==r) return;
    int mid=(l+r)>>1;
    if(p<=mid) fIns(lc(x),l,mid,p);
    else fIns(rc(x),mid+1,r,p);
}
int fQue(int x,int y,int l,int r,ll m){
    //printf("fQue %d %d %d %d  %d %d %lld %lld\n",x,y,l,r,t[x].size,t[y].size,t[x].sum,t[y].sum);
    if(l==r){
        ll lsum=t[y].sum-t[x].sum;
        return lsum<=m ? t[y].size-t[x].size : 0;
    }else{
        int mid=(l+r)>>1;
        ll lsum=t[lc(y)].sum-t[lc(x)].sum;//printf("lsum %lld %lld\n",lsum,m);
        if(m<=lsum) return fQue(lc(x),lc(y),l,mid,m);
        else return t[lc(y)].size-t[lc(x)].size+fQue(rc(x),rc(y),mid+1,r,m-lsum);
    }
}
int rt=0,u;
int main(){
    freopen("in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=n;i++){
        u=read();if(u==0) rt=i;
        ins(u,i),a[i].w=read(),a[i].li=read(),a[i].id=i;
    }
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++) mp[i]=a[i].w,a[i].w=i;
    sort(a+1,a+1+n,cmpId);
    //for(int i=1;i<=n;i++) printf("a %d %d %d\n",a[i].id,a[i].w,mp[a[i].w]);
    dfs(rt,0);
    //for(int i=1;i<=n;i++) printf("LR %d %d %d\n",i,L[i],R[i]);
    //for(int i=1;i<=n;i++) printf("%d ",pos[i]);puts("");
    for(int i=1;i<=n;i++) root[i]=root[i-1],fIns(root[i],1,n,a[pos[i]].w);
    ll ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,(ll)a[i].li*fQue(root[L[i]-1],root[R[i]],1,n,m));
    printf("%lld",ans);
}
时间: 2025-01-05 23:49:44

BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]的相关文章

【BZOJ 2809】dispatching(主席树)

这道题用主席树做做感觉非常舒服~~~ 首先题意来看,是说需要在树形结构中找到一个点i,并且找到这个点子树中的一些点组成一个集合,使得集合中的c之和不超过M,且Li*集合中元素个数和最大 简单地想想首先需要枚举每一个点,然后在子树中找到最小的k个点,使得sigma(C[i])(i = 1..k)不超过M,那么L[i]*k就是对于这个点来说的最优解 那么我们应该想到可以利用主席树中的性质,首先将树形结构通过dfs序转化到线性结构上,然后可以通过对子树中的记录信息进行判断从而得到答案(详见代码) 再想

bzoj 3772 精神污染 主席树+dfs序

精神污染 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 637  Solved: 177[Submit][Status][Discuss] Description 兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是集经济和文化于一体的一大地区,是日本西部门户,海陆空交通设施发达.濑户内海沿岸气候温暖,多晴天,有日本少见的贸易良港神户港所在的神户市和曾是豪

51 nod 1681 公共祖先 (主席树+dfs序)

1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另一个未知的平行宇宙,这n人的祖辈关系仍然是树形结构,但他们相互之间的关系却完全不同了,原来的祖先可能变成了后代,后代变成的同辈…… 两个人的亲密度定义为在这两个平行宇宙有多少人一直是他们的公共祖先. 整个家族的亲密度定义为任意两个人亲密度的总和. Input 第一行一个数n(1<=n<=100000)

【BZOJ1803】Spoj1487 Query on a tree III 主席树+DFS序

[BZOJ1803]Spoj1487 Query on a tree III Description You are given a node-labeled rooted tree with n nodes. Define the query (x, k): Find the node whose label is k-th largest in the subtree of the node x. Assume no two nodes have the same labels. Input

P2633|主席树+dfs序+树链剖分求lca+离散化

不知道为什么会RE.. 待补 思路:链上求u和v两点路径第k小利用lca就转变为了 U+V-LCA-FA(LCA) 上的第k小,这因为每个点的主席树的root是从其父转移来的.可以用树链剖分求lca:在dfs序上建立主席树将树上问题转变为区间问题,询问的时候用主席树求区间k小值. 终于能写出这种题了,开心! #include<bits/stdc++.h> using namespace std; const int maxn = 1e5+100; int n,m,e = 1,num,ans=0

P3899|主席树+dfs序

理解题意后分两种情况: 1.b在a的上方: min(dep[p]-1,k)*(ll)siz[p] 因为(p点上方肯定有父亲结点b,我们不用管b是谁) 2.b在a的下方: (dep(p)+1 ~ dep(p)+k矩形框内的所有点子树个数和 所以思路:主席树维护同一深度下的各个结点子树个数和:下标是深度,权值维护的是子树个数和:在dfs序in和out时间戳上建立主席树,把树上问题转变为区间序列问题,利用dfs序时间戳的性质(子树编号在入时间戳和出时间戳的区间内),查询以p为根子树:所以问题就转变为了

BZOJ_1803_Spoj1487 Query on a tree III_主席树+dfs序

BZOJ_1803_Spoj1487 Query on a tree III_主席树 Description You are given a node-labeled rooted tree with n nodes. Define the query (x, k): Find the node whose label is k-th largest in the subtree of the node x. Assume no two nodes have the same labels. I

[BZOJ 2809][Apio2012]dispatching(左偏树)

Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都有且仅有一个上级.为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是由上级发送给他的直接下属,而不允许通过其他的方式发送.现在你要招募一批忍者,并把它们派遣给顾客.你需要为每个被派遣的忍者 支付一定的薪水,同时使得支付的薪水总额不超过你的预算.另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者

BZOJ 2809 APIO2012 dispatching Treap+启示式合并 / 可并堆

题目大意:给定一棵树,选定一棵子树中的一些点,薪水和不能超过m,求点的数量*子树根节点的领导能力的最大值 考虑对于每一个节点,我们维护一种数据结构,在当中贪心寻找薪金小的雇佣. 每一个节点暴力重建一定不行.我们考虑可并数据结构.每一个节点将子节点的信息直接合并就可以 能够用启示式合并的Treap.也能够用可并堆 今天特意去学了这玩应0.0 先写了左偏树 然后又写了下随机堆-- 后者速度上更快一些 只是建议从左偏树開始学起 总之平衡树常数各种大就是了0.0 Treap+启示式合并 #include