您的位置:首页 > 其它

[可并堆学习]

2016-06-01 20:31 162 查看

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

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: