您的位置:首页 > 其它

bzoj 3192: [JLOI2013]删除物品

2017-09-18 10:31 309 查看
题意:有两堆物品,每个物品有个权值。每次可以将其中一个堆的顶端的物品移到另一堆的顶端,假如它的权值是所有物品里最大的,就可以把它删掉。问最少几次移动可以删除所以物品。

题解:直接模拟+线段树。

跑的贼慢。。。

#include<bits/stdc++.h>
using namespace std;

int n1,n2,n,num=0,a[100010];
struct tree
{
int l,r,lc,rc,s,m;
}tr[200010];
long long ans=0;
map<int,int>pos;

int bt(int l,int r)
{
int i=++num;
tr[i]={l,r,0,0,1,a[l]};
if(l<r)
{
int md=l+r>>1;
tr[i].lc=bt(l,md);
tr[i].rc=bt(md+1,r);
tr[i].s=tr[tr[i].lc].s+tr[tr[i].rc].s;
tr[i].m=max(tr[tr[i].lc].m,tr[tr[i].rc].m);
}
return i;
}
void chg(int i,int x,int y)
{
if(tr[i].l==tr[i].r)
{
tr[i].s=tr[i].m=y;
return;
}
int md=tr[i].l+tr[i].r>>1,lc=tr[i].lc,rc=tr[i].rc;
if(x<=md)
chg(lc,x,y);
else
chg(rc,x,y);
tr[i].s=tr[lc].s+tr[rc].s;
tr[i].m=max(tr[lc].m,tr[rc].m);
}
int get(int i,int l,int r)
{
if(l>r)
return 0;
if(tr[i].l==l&&tr[i].r==r)
return tr[i].s;
int md=tr[i].l+tr[i].r>>1,lc=tr[i].lc,rc=tr[i].rc;
if(r<=md)
return get(lc,l,r);
else if(l>md)
return get(rc,l,r);
else
return get(lc,l,md)+get(rc,md+1,r);
}
int main()
{
scanf("%d%d",&n1,&n2);
n=n1+n2;
for(int i=n1;i>0;i--)
{
scanf("%d",&a[i]);
pos[a[i]]=i;
}
for(int i=n1+1;i<=n;i++)
{
scanf("%d",&a[i]);
pos[a[i]]=i;
}
bt(1,n);
int p=n1;
for(int i=1;i<=n;i++)
{
int hh=pos[tr[1].m];
if(hh<=p)
{
ans+=get(1,hh+1,p);
}
else
{
ans+=get(1,p+1,hh-1);
}
chg(1,hh,0);
//      printf("%d %d %lld\n",p,hh,ans);
p=hh;
}
printf("%lld",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: