您的位置:首页 > 其它

2809: [Apio2012]dispatching 启发式合并treap 可并堆

2016-02-21 09:05 369 查看
我曾写过N次启发式合并splay。。由于太弱从来没调出来过。。

这次写了一发treap终于过啦!(然而常数太大被可并堆虐成狗了)

首先,作法显然,从底向上,每次计算子树的前k小数保证和<=M,然后将两棵子树合并,更新答案。

显然treap和可并堆都是支持这些操作的。不过treap合并的时候有很多无效的节点一直在合并,如果能split的话应该能快一些吧(然而我不会)。

treap:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define N 100005
#define ll long long
using namespace std;
int n,cnt,tmp;
ll ans,M;
int next[N<<1],list[N<<1];
int head
,f
,size
,root
,rnd
,ls
,rs
;
ll sum
,val
,c
,l
;
inline ll read()
{
ll a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void addedge(int x,int y)
{
next[++cnt]=head[x];
head[x]=cnt;
list[cnt]=y;
}
int find(int i)
{
return f[i]==i?i:f[i]=find(f[i]);
}
inline void pushup(int k)
{
size[k]=size[ls[k]]+size[rs[k]]+1;
sum[k]=sum[ls[k]]+sum[rs[k]]+val[k];
}
inline void lturn(int &k)
{
int t=rs[k]; rs[k]=ls[t]; ls[t]=k; pushup(k); pushup(t); k=t;
}
inline void rturn(int &k)
{
int t=ls[k]; ls[k]=rs[t]; rs[t]=k; pushup(k); pushup(t); k=t;
}
void insert(int &k,ll x,int y)
{
if (!k)
{
k=y;
size[k]=1;
sum[k]=x;
val[k]=x;
rnd[k]=rand();
return;
}
size[k]++; sum[k]+=x;
if (x<=val[k])
{
insert(ls[k],x,y);
if (rnd[ls[k]]>rnd[k]) rturn(k);
}
else
{
insert(rs[k],x,y);
if (rnd[rs[k]]>rnd[k]) lturn(k);
}
}
void merge(int x,int &y)
{
if (!x) return;
merge(ls[x],y);
merge(rs[x],y);
ls[x]=rs[x]=0;
insert(y,c[x],x);
}
void find_max(int k,ll MAXN)
{
if (!k) return;
if (sum[ls[k]]+val[k]<=MAXN) tmp+=size[ls[k]]+1,find_max(rs[k],MAXN-sum[ls[k]]-val[k]);
else if (sum[ls[k]]<=MAXN) {tmp+=size[ls[k]]; return;}
else find_max(ls[k],MAXN);
}
void dfs(int x)
{
if (!head[x]) {ans=max(ans,l[x]); return;}
for (int i=head[x];i;i=next[i]) dfs(list[i]);
for (int i=head[x];i;i=next[i])
{
int p=find(x),q=find(list[i]);
if (size[root[p]]>size[root[q]]) swap(p,q);
merge(root[p],root[q]); f[p]=q;
}
int p=find(x);
tmp=0;
find_max(root[p],M);
ans=max(ans,tmp*l[x]);
}
int main()
{
n=read(); M=read();
for (int i=1;i<=n;i++) f[i]=i;
for (int i=1;i<=n;i++)
{
int x=read(); c[i]=read(); l[i]=read();
if (x) addedge(x,i);
insert(root[i],c[i],i);
}
dfs(1);
cout << ans << endl;
return 0;
}


可并堆:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define N 100005
#define ll long long
using namespace std;
int n,cnt;
ll M,ans;
ll l
,c
,sum
;
int ls
,rs
,d
,root
,head
,next
,list
,size
;
inline ll read()
{
ll a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void insert(int x,int y)
{
next[++cnt]=head[x];
head[x]=cnt;
list[cnt]=y;
}
int merge(int x,int y)
{
if (!x||!y) return x+y;
if (c[x]<c[y]) swap(x,y);
sum[x]+=sum[y];
size[x]+=size[y];
rs[x]=merge(rs[x],y);
if (d[rs[x]]>d[ls[x]]) swap(ls[x],rs[x]);
d[x]=d[rs[x]]+1;
return x;
}
int main()
{
n=read(); M=read();
for (int i=1;i<=n;i++)
{
int x=read(); c[i]=read(); l[i]=read();
if (x) insert(x,i); root[i]=i; sum[i]=c[i]; size[i]=1;
}
for (int x=n;x;x--)
{
for (int i=head[x];i;i=next[i])
root[x]=merge(root[x],root[list[i]]);
while (sum[root[x]]>M) root[x]=merge(ls[root[x]],rs[root[x]]);
ans=max(ans,size[root[x]]*l[x]);

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