[可并堆学习]
happy children's day!
【bzoj2809】【APIO2012】dispatching
dispatch:派遣,调度,快速处理的意思
题意可以简化为,找max{L[u]*可取的子数结点最大值},并且使所取结点薪水和小于M,即取最小几项。
n为10w,暴力显然会T。
考虑到递归的过程中,较大的子节点不被取,以后更加不会取,所以只需将较大的子节点弹出栈即可。
关于可并堆的写法,记录它的左节点与右结点,在这道题里,是小的并到大处,千万别忘了将他们左右结点再调换一下。
#include<cstdio> #define N 200000 #define ll long long #include<algorithm> using namespace std; ll now=0,ans=0,l ; int edgenum,top,n,m; int vet ,size ,root ,le ,rr ,head ,next ,a ,c ; ll sum ; void add(int u,int v) { edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum; } int merge(int x,int y) { if(x==0||y==0)return x+y;if(c[x]<c[y])swap(x,y); rr[x]=merge(rr[x],y);swap(le[x],rr[x]);return x; } void dfs(int u) { int e=head[u];size[u]=1;sum[u]=c[u];root[u]=u; while(e>0) { int v=vet[e]; dfs(v);sum[u]+=sum[v];size[u]+=size[v]; root[u]=merge(root[u],root[v]); e=next[e]; } while(sum[u]>m){ sum[u]-=c[root[u]];size[u]--;root[u]=merge(le[root[u]],rr[root[u]]); } if(size[u]*l[u]>ans)ans=size[u]*l[u]; } int main() { scanf("%d%d",&n,&m);int x; for(int i=1;i<=n;i++) { scanf("%d%d%lld",&x,&c[i],&l[i]); add(x,i); } dfs(1);printf("%lld",ans); }
【bzoj1455】
没有做,口胡一下。
【bzoj1367】【baltic2004】sequence
并不知道这是个什么比赛。。。
讨论版里seter大神的友情提示:小心内存。。。听说线段树不小心可过?
然而我实在想不到它与可并堆有何关系?
ok....这是一道05年的论文题,这里需要用到左偏树。(简而言之,向左偏的树)这个百度文库里已经讲得很优秀了。
左偏树具有两个属性,键值与距离(i结点到最近外结点的边数),如果i本身是外节点,则dist=0,若i为空结点,则dist=NULL;
当我们要合并A与B,若它们均非空,则合并right(A)与B,这里我们默认A的根键值小于B(小根堆的情况下);
当合并之后,A“往右偏了”,我们再将它的左右儿子调换一下即可;然后别忘了更新distA;
合并的复杂度在最坏情况下是O(logN1+logN2)。
THEN, ABOUT ADD:
对于插入一个新节点的情况,我们只需看成两左偏树的合并,复杂度是o(logn)
DELETE:
删除根节点后,只需将左右子树再合并(将左右子树都记录下来);
BUILD:
创建一棵左偏树,如果暴力操作,此时复杂度为O(NlogN),只需要一个一个结点插入;
删除任意一个结点:
暂不学习
#include<cstdio> #include<algorithm> #define ll long long #define N 401000 using namespace std; ll pri ,l; int edgenum,n,vet ,head ,next ,ans ,le ,rr ,node=0; struct wxx{ int size,id; ll max,mark; }root ; void add(int u,int v,ll w) { edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum;pri[edgenum]=w; } void Add(int a ,ll val) { root[a].max+=val;root[a].mark+=val; //printf("nowoo===%lld\n",root[a].max); } void push_down(int x) { if(root[x].mark) { if(le[x])Add(le[x],root[x].mark); if(rr[x])Add(rr[x],root[x].mark); }root[x].mark=0; } int merge(int x,int y) { if(x==0||y==0)return x+y; //printf("===%d %d\n",root[x].max,root[4].max); if(root[x].max<root[y].max)swap(x,y); //printf("===%d %d\n",x,y); push_down(x); rr[x]=merge(rr[x],y); swap(le[x],rr[x]); root[x].size=root[le[x]].size+root[rr[x]].size+1; return x; } void dfs(int u,int fa) { int e=head[u];root[u].size=1;root[u].max=0;root[u].id=u; while(e>0) { int v=vet[e]; if(v!=fa){ dfs(v,u); // printf("add==%d %lld\n",root[v].id,pri[e]); Add(root[v].id,pri[e]); root[u].id=merge(root[u].id,root[v].id); } e=next[e]; } //printf("%d %d %lld %d\n",u,root[u].id,root[root[u].id].max,root[root[u].id].size); while(root[root[u].id].size>0&&root[root[u].id].max>l) { push_down(root[u].id); root[root[u].id].size--; root[u].id=merge(le[root[u].id],rr[root[u].id]); } ans[u]=root[root[u].id].size; } int main() { freopen("rand.out","r",stdin);freopen("cuo.out","w",stdout); scanf("%d%lld",&n,&l); for(int i=2;i<=n;i++) { int v;ll len; scanf("%d%lld",&v,&len);add(v,i,len); } dfs(1,0); for(int i=1;i<=n;i++)printf("%d\n",ans[i]); }bzoj3011
- C#之四十 Winform MD5加密
- C#之四十 Winform MD5加密
- FFT 模板
- 12.2.12 创建有响应的用户界面 捕获异常
- c++-可变参数模板函数
- JAVA 集合框架学习笔记
- zabbix 主机名必须要能ping通
- Skyline学习系列 01 如何通过SFS发布shape文件
- 使用 Redis 实现分布式系统轻量级协调技术
- zabbix 主机名必须要能ping通
- zabbix 主机名必须要能ping通
- Apache Flume 分布式日志收集系统学习
- y
- [iOS] 判断tableView向上或向下滑动
- android activity四种加载模式
- 站立会议04(第二期)
- unity 协程
- Error “You must not call setTag() on a view Glide is targeting” when use Glide
- Linux常用命令
- gulp详细入门教程