ZOJ2112 & BZOJ1901 玩坏了的主席树

今天才发现加上回收空间的话主席树的空间是nlognlogn→ →之前总当成和树套树一样是nlogn了【你特喵在逗我

在BZOJ上很久前过掉了,今天滚回来写ZOJ各种卡空间

ZOJ上32768K实在是……卡死了

所以,为了压缩空间,我们拆成两部分来做。

首先静态建树,直接把给定的序列离散化丢到一棵树里【就像POJ2104那样玩】,这里的空间是nlogn,如果直接用树状数组去套的话空间就是nlognlogn在ZOJ上就无限MLE了……

那么更新怎么办呢?

再造一棵树用来记录更新,这棵树要用树状数组来套,这里的空间最多是mlognlogn。

这样总的空间复杂度就是nlogn+mlognlogn,因为总的操作数m<=10000,但是n<=50000,于是空间就降下来了,在ZOJ上基本上31000K左右的空间就能AC了。

这方法玩得真脱呀……………………

ZOJ 2112
#define NN 50005
#define NM 10005
#define MM 2600010
int root[NN],rt1[NN],a[NN],b[NN+NM],n,q,node,lb,poi;
int ord[NM][4]; int bit[NN];
struct sgtree{ int l,r,s; }tree[MM];
int sta[NM],top;
int fastget()
{
	char c; int ans=0; c=getchar();
	while (! (c>='0' && c<='9')) c=getchar();
	while (c>='0' && c<='9')
	{
		ans=(ans<<3)+(ans<<1)+c-'0';
		c=getchar();
	}
	return ans;
}
int search(int x)
{
	int l=1,r=b[0],mid;
	while (l<=r)
	{
		mid=l+r>>1; if(b[mid]==x) return mid;
		if(b[mid]<x) l=mid+1; else r=mid-1;
	}
}
int build(int l,int r)
{
	int k=++node;
	tree[k].s=0;
	if(l==r) return k;
	int mid=l+r>>1;
	if(l<=mid) tree[k].l=build(l,mid);
	if(r>mid) tree[k].r=build(mid+1,r);
	return k;
}
int sum(int x)
{
	int ans=0;
	for(;x;x-=lowbit(x)) ans+=tree[tree[bit[x]].l].s;
	return ans;
}
int query(int x,int y,int xx,int yy,int l,int r,int k)
{
	if(l==r) return l;
	int ans=tree[tree[yy].l].s-tree[tree[xx].l].s+sum(y)-sum(x);
	int mid=l+r>>1;
	if(ans>=k)
	{
		for(int i=x;i;i-=lowbit(i)) bit[i]=tree[bit[i]].l;
		for(int i=y;i;i-=lowbit(i)) bit[i]=tree[bit[i]].l;
		return query(x,y,tree[xx].l,tree[yy].l,l,mid,k);
	}
	else
	{
		for(int i=x;i;i-=lowbit(i)) bit[i]=tree[bit[i]].r;
		for(int i=y;i;i-=lowbit(i)) bit[i]=tree[bit[i]].r;
		return query(x,y,tree[xx].r,tree[yy].r,mid+1,r,k-ans);
	}
}
int update(int rt,int l,int r,int x,int d)
{
	int k=++node;
	tree[k]=tree[rt];
	tree[k].s+=d;
	if(l==r) return k;
	int mid=l+r>>1;
	if(x<=mid) tree[k].l=update(tree[rt].l,l,mid,x,d);
	else tree[k].r=update(tree[rt].r,mid+1,r,x,d);
	return k;
}
int main()
{
freopen("1.in","r",stdin);
	int tt=fastget();
	while(tt--)
	{
		top=node=0;
		lb=n=fastget(); q=fastget();
		for(int i=1;i<=n;i++) b[i]=a[i]=fastget();
		for(int i=1;i<=q;i++)
		{
			char s[3]; scanf("%s",s);
			if(s[0]=='Q'){ ord[i][0]=1; ord[i][1]=fastget(); ord[i][2]=fastget(); ord[i][3]=fastget(); }
			else{ ord[i][0]=2; ord[i][1]=fastget(); b[++lb]=ord[i][2]=fastget(); }
		}
		sort(b+1,b+1+lb); b[0]=1;
		for(int i=2;i<=lb;i++) if(b[i]!=b[b[0]]) b[++b[0]]=b[i];
		for(int i=1;i<=n;i++) a[i]=search(a[i]);
		root[0]=build(1,b[0]); poi=node;
		for(int i=1;i<=n;i++) rt1[i]=root[0];
		for(int i=1;i<=n;i++)
			root[i]=update(root[i-1],1,b[0],a[i],1);
		for(int _=1;_<=q;_++)
		{
			if(ord[_][0]==1)
			{
				int u=ord[_][1],v=ord[_][2],w=ord[_][3];
				for(int i=u-1;i;i-=lowbit(i)) bit[i]=rt1[i];
				for(int i=v;i;i-=lowbit(i)) bit[i]=rt1[i];
				printf("%d\n",b[query(u-1,v,root[u-1],root[v],1,b[0],w)]);
			}
			else
			{
				int u=ord[_][1],w=ord[_][2];
				for(int i=u;i<=n;i+=lowbit(i)) rt1[i]=update(rt1[i],1,b[0],a[u],-1);
				a[u]=search(w);
				for(int i=u;i<=n;i+=lowbit(i)) rt1[i]=update(rt1[i],1,b[0],a[u],1);
			}
		}
	}
	return 0;
}


蛋疼的nlognlogn的空间的方法【BZOJ1901】

#define NN 10005
#define NM 10005
#define MM 2500010
int root[NN],a[NN],b[NN+NM],n,q,node,lb,poi;
int ord[NM][4]; int bit[NN];
struct sgtree{ int l,r,s; }tree[MM];
int sta[NM],top;
int fastget()
{
    char c; int ans=0; c=getchar();
    while (! (c>='0' && c<='9')) c=getchar();
    while (c>='0' && c<='9')
    {
        ans=(ans<<3)+(ans<<1)+c-'0';
        c=getchar();
    }
    return ans;
}
int search(int x)
{
    int l=1,r=b[0],mid;
    while (l<=r)
    {
        mid=l+r>>1; if(b[mid]==x) return mid;
        if(b[mid]<x) l=mid+1; else r=mid-1;
    }
}
int build(int l,int r)
{
    int k=++node;
    tree[k].s=0;
    if(l==r)
    {
        tree[k].l=tree[k].r=0;
        return k;
    }
    int mid=l+r>>1;
    if(l<=mid) tree[k].l=build(l,mid);
    if(r>mid) tree[k].r=build(mid+1,r);
    return k;
}
int sum(int x)
{
    int ans=0;
    for(;x;x-=lowbit(x)) ans+=tree[tree[bit[x]].l].s;
    return ans;
}
int query(int x,int y,int l,int r,int k)
{
    if(l==r) return l;
    int ans=sum(y)-sum(x);
    int mid=l+r>>1;
    if(ans>=k)
    {
        for(int i=x;i;i-=lowbit(i)) bit[i]=tree[bit[i]].l;
        for(int i=y;i;i-=lowbit(i)) bit[i]=tree[bit[i]].l;
        return query(x,y,l,mid,k);
    }
    else
    {
        for(int i=x;i;i-=lowbit(i)) bit[i]=tree[bit[i]].r;
        for(int i=y;i;i-=lowbit(i)) bit[i]=tree[bit[i]].r;
        return query(x,y,mid+1,r,k-ans);
    }
}
int update(int rt,int l,int r,int x,int d)
{
    int k;
    if(top) k=sta[--top];
    else k=++node;
    tree[k]=tree[rt];
    tree[k].s+=d;
    if(l==r)
    {
        tree[k].l=tree[k].r=0;
        return k;
    }
    int mid=l+r>>1;
    if(x<=mid)
    {
        if(tree[k].l>poi) sta[top++]=tree[k].l;
        tree[k].l=update(tree[rt].l,l,mid,x,d);
    }
    else
    {
        if(tree[k].r>poi) sta[top++]=tree[k].r;
        tree[k].r=update(tree[rt].r,mid+1,r,x,d);
    }
    return k;
}
int main()
{
        top=node=0;
        lb=n=fastget(); q=fastget();
        for(int i=1;i<=n;i++) b[i]=a[i]=fastget();
        for(int i=1;i<=q;i++)
        {
            char s[3]; scanf("%s",s);
            if(s[0]=='Q'){ ord[i][0]=1; ord[i][1]=fastget(); ord[i][2]=fastget(); ord[i][3]=fastget(); }
            else{ ord[i][0]=2; ord[i][1]=fastget(); b[++lb]=ord[i][2]=fastget(); }
        }
        sort(b+1,b+1+lb); b[0]=1;
        for(int i=2;i<=lb;i++) if(b[i]!=b[b[0]]) b[++b[0]]=b[i];
        for(int i=1;i<=n;i++) a[i]=search(a[i]);
        root[0]=build(1,b[0]); poi=node;
        for(int i=1;i<=n;i++) root[i]=root[0];
        for(int i=1;i<=n;i++)
        for(int x=i;x<=n;x+=lowbit(x))
            root[x]=update(root[x],1,b[0],a[i],1);
        for(int _=1;_<=q;_++)
        {
            if(ord[_][0]==1)
            {
                int u=ord[_][1],v=ord[_][2],w=ord[_][3];
                for(int i=u-1;i;i-=lowbit(i)) bit[i]=root[i];
                for(int i=v;i;i-=lowbit(i)) bit[i]=root[i];
                printf("%d\n",b[query(u-1,v,1,b[0],w)]);
            }
            else
            {
                int u=ord[_][1],w=ord[_][2];
                for(int i=u;i<=n;i+=lowbit(i)) root[i]=update(root[i],1,b[0],a[u],-1);
                a[u]=search(w);
                for(int i=u;i<=n;i+=lowbit(i)) root[i]=update(root[i],1,b[0],a[u],1);
            }
        }
    return 0;
}



评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值