主席树学习记录

搞了一段时间网络流后,最后还是回到了数据结构。。。

主席树,引fotile主席的一段话:

..这个东西是当初我弱不会划分树的时候写出来替代的一个玩意..被一小撮别有用心的人取了很奇怪的名字> <
想法是对原序列的每一个前缀[1..i]建立出一颗线段树维护值域上每个数的出现次数,然后发现这样的树是可以减的,然后就没有然后了

其实是一种比较好理解的数据结构(至少静态查找时是如此),我们对于每个点,建一个类似与前缀和的线段树,然后我们发现这样的n棵线段树是可以相减的,于是。。。但是在实现过程中,由于内存限制的原因,我们一般用指针实现。

COGS 930 找第k小的数。裸题,直接上模板。code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid (l+r)/2
using namespace std;
struct node{
	node *left,*right;
	int a,size;
	node(){left=right=NULL; size=a=0;}
	int updata()
	  {
	  	size=a;
	    if (left) size+=left->size;
	    if (right) size+=right->size;
	  }
}*null=new node(),*root[100001]={NULL},q[2000001];
int n,m,a[100001],b[100001];
int temp,ans;
void build(node *&y,node *&x,int l,int r,int t)
{
	if (x==NULL) x=null;
	y=&q[++temp]; 
	*y=node();
	if (l==r)
	  {
	    *y=*x; y->size++; y->a++;
		return;  
	  }
	if (t<=b[mid])
	  {
	    build(y->left,x->left,l,mid,t);
	    y->right=x->right;
	    y->updata();
	  }
	else
	  {
	    build(y->right,x->right,mid+1,r,t);
	    y->left=x->left;
	    y->updata();
	  }
}
void find(node *x1,node *x2,int l,int r,int k)
{
	int ls;
	if (x1==NULL) x1=null; if (x2==NULL) x2=null;
	ls=0;
	if (l==r) {ans=b[l]; return;}
	if (x2->left) ls+=x2->left->size;
	if (x1->left) ls-=x1->left->size;
	if (ls>=k) find(x1->left,x2->left,l,mid,k);
	else find(x1->right,x2->right,mid+1,r,k-ls);
}
int main()
{
	int i,size,x,l,r,k;
	freopen("kth.in","r",stdin);
	freopen("kth.out","w",stdout);
	scanf("%d%d",&n,&m);
	null->left=null; null->right=null;
	for (i=1;i<=n;++i)
	  {
	    scanf("%d",&a[i]);
	    b[i]=a[i];
	  }
	sort(b+1,b+n+1);
	size=unique(b+1,b+n+1)-b-1;
	temp=0;
	for (i=1;i<=n;++i)
	  build(root[i],root[i-1],1,size,a[i]);
	for (i=1;i<=m;++i)
	  {
	    scanf("%d%d%d",&l,&r,&k);
	    ans=0; find(root[l-1],root[r],1,size,k);
	    printf("%d\n",ans);
	  }
	fclose(stdin);
	fclose(stdout);
}

动态主席树,其实救是树状数组套线段树,COGS 257 动态排名系统 code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid (l+r)/2
using namespace std;
struct hp{
	int size,l,r;
}tree[10000001];
struct hq{
	char op;
	int x,y,k;
}qst[10001];
int t,n,m,tot,size;
int root[50001],a[50001],b[60001],q1[2000],q2[2000];
int lowbit(int x) {return x&(-x); }
void build(int &x,int l,int r)
{
	tree[x=++tot].size=0;
	if (l==r) return;
	build(tree[x].l,l,mid); 
	build(tree[x].r,mid+1,r);
}
void insert(int last,int &i,int l,int r,int x,int flag)
{
	tree[i=++tot].size=tree[last].size+flag;
	tree[i].l=tree[last].l; tree[i].r=tree[last].r;
	if (l==r) return;
	if (x<=mid) insert(tree[last].l,tree[i].l,l,mid,x,flag);
	else insert(tree[last].r,tree[i].r,mid+1,r,x,flag);
}
void bit_ins(int i,int x,int flag)
{
	for (;i<=n;i+=lowbit(i)) insert(root[i],root[i],1,size,x,flag);
}
int ask(int l,int r,int k)
{
	int ss=0,i;
	if (l==r) return l;
	for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].l].size;
	for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].l].size;
	if (k<=ss)
	  {
	    for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].l;
	    for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].l;
	    return ask(l,mid,k);
	  }
	else
	  {
	    for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].r;
	    for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].r;
	    return ask(mid+1,r,k-ss);
	  }
}
int bit_ask(int l,int r,int k)
{
	q2[0]=q1[0]=0;
	for (;r;r-=lowbit(r)) q2[++q2[0]]=root[r];
	for (;l;l-=lowbit(l)) q1[++q1[0]]=root[l];
	return ask(1,size,k);
}
int main()
{
	int i,j;
	freopen("dynrank.in","r",stdin);
	freopen("dynrank.out","w",stdout);
	scanf("%d",&t);
	while (t)
	  {
	    memset(root,0,sizeof(root));
	    memset(tree,0,sizeof(tree));
	    tot=0; b[0]=0; 
	    scanf("%d%d",&n,&m);
	    for (i=1;i<=n;++i)
	      {
	        scanf("%d",&a[i]);
	        b[0]++;b[b[0]]=a[i];
	      }
        for (i=1;i<=m;++i)
          {
            scanf("%*c%c",&qst[i].op);
            if (qst[i].op=='Q')
              scanf("%d%d%d",&qst[i].x,&qst[i].y,&qst[i].k);
            else
              {
                scanf("%d%d",&qst[i].x,&qst[i].k);
                b[0]++; b[b[0]]=qst[i].k;
              }
          }
        sort(b+1,b+b[0]+1);
        size=unique(b+1,b+b[0]+1)-b-1;
        build(root[0],1,size);
        for (i=1;i<=n;++i) 
          {
            a[i]=upper_bound(b+1,b+size+1,a[i])-b-1;
            bit_ins(i,a[i],1);
          }
        for (i=1;i<=m;++i)
          {
            if (qst[i].op=='Q')
              {
                j=bit_ask(qst[i].x-1,qst[i].y,qst[i].k);
                printf("%d\n",b[j]);
              }
            else
              {
                bit_ins(qst[i].x,a[qst[i].x],-1);
                a[qst[i].x]=upper_bound(b+1,b+size+1,qst[i].k)-b-1;
                bit_ins(qst[i].x,a[qst[i].x],1);
              }
          }
        t--;
	  }
	fclose(stdin);
	fclose(stdout);
}

其实稍微转化一下就成模板题啦~~ code:

#include<iostream>
#include<cstdio>
#include<cstring>
#define mid (l+r)/2
using namespace std;
struct hp{
	int size,l,r;
}tree[10000000];
int root[100001],q1[2000],q2[2000],n,m;
int a[100001],a2[100001],c[100001],pos[100001],tot,del[100001];
long long ansi[50001]={0};
int lowbit(int x) { return x&(-x); }
long long work(int l,int r)
{
	int i,j;
	int ans=0;
	if (l==r) return ans;
	ans+=work(l,mid)+work(mid+1,r);
	i=l; j=mid+1; c[0]=0;
	while (i<=mid&&j<=r)
	  {
	    if (a2[i]<a2[j])
	      {
	        c[++c[0]]=a2[i];
	        i++;
	      }
	    else
	      {
	        c[++c[0]]=a2[j]; j++;
	        ans+=mid-i+1;
	      }
	  }
	for (;i<=mid;++i) c[++c[0]]=a2[i];
	for (;j<=r;++j) c[++c[0]]=a2[j];
	for (i=l;i<=r;++i) a2[i]=c[i-l+1];
	return ans;
}
void build(int &x,int l,int r)
{
	tree[x=++tot].size=0;
	if (l==r) return;
	build(tree[x].l,l,mid); 
	build(tree[x].r,mid+1,r);
}
long long askless(int l,int r,int x)
{
	int ss=0;
	int i;
	if (l==r) return 0;
	for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].l].size;
	for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].l].size;
	if (x<=mid)
	  {
	    for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].l;
	    for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].l;
	    return askless(l,mid,x);
	  }
	else
	  {
	    for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].r;
	    for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].r;
	    return ss+askless(mid+1,r,x);  
	  }
}
long long askmore(int l,int r,int x)
{
	int ss=0;
	int i;
	if (l==r) return 0;
	for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].r].size;
	for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].r].size;
	if (x>mid)
	  {
	    for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].r;
	    for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].r;
	    return askmore(mid+1,r,x);
	  }
	else
	  {
	    for (i=1;i<=q2[0];++i) q2[i]=tree[q2[i]].l;
	    for (i=1;i<=q1[0];++i) q1[i]=tree[q1[i]].l;
	    return ss+askmore(l,mid,x);  
	  }
}
long long bit_askless(int l,int r,int x)
{
	q1[0]=q2[0]=0;
	for (;l;l-=lowbit(l)) q1[++q1[0]]=root[l];
	for (;r;r-=lowbit(r)) q2[++q2[0]]=root[r];
	askless(1,n,x);
}
long long bit_askmore(int l,int r,int x)
{
	q1[0]=q2[0]=0;
	for (;l;l-=lowbit(l)) q1[++q1[0]]=root[l];
	for (;r;r-=lowbit(r)) q2[++q2[0]]=root[r];
	askmore(1,n,x);
}
void insert(int last,int &i,int l,int r,int x,int flag)
{
	if (!i) i=++tot;
	tree[i].size=tree[last].size+flag;
	tree[i].l=tree[last].l; tree[i].r=tree[last].r;
	if (l==r) return; 
	if (x<=mid) insert(tree[last].l,tree[i].l,l,mid,x,flag);
	else insert(tree[last].r,tree[i].r,mid+1,r,x,flag);
}
void bit_ins(int i,int x,int flag)
{
	for (;i<=n;i+=lowbit(i)) insert(root[i],root[i],1,n,x,flag);
}
int main()
{
	int i; long long ans=0;
	scanf("%d%d",&n,&m); tot=0;
	for (i=1;i<=n;++i)
	  {
	    scanf("%d",&a[i]);
	    pos[a[i]]=i;
      }
    for (i=1;i<=m;++i)
      {
        scanf("%d",&del[i]);
        a[pos[del[i]]]=0;
      }
    build(root[0],1,n);
    for (i=1;i<=n;++i)
      if (a[i])
        {
          bit_ins(i,a[i],1);
		  a2[++a2[0]]=a[i];  
        }
    ans=work(1,a2[0]);
    for (i=m;i>=1;--i)
      {
        bit_ins(pos[del[i]],del[i],1);
        if (pos[del[i]]>1) ans+=bit_askmore(0,pos[del[i]]-1,del[i]); 
        if (pos[del[i]]<n) ans+=bit_askless(pos[del[i]],n,del[i]);   
        ansi[i]=ans;
      }
    for (i=1;i<=m;++i)
      printf("%lld\n",ansi[i]);
}



 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值