树套树 初见

跟随着潮流,弱弱的学习了一下主席树。明白了思想之后,第一次比较快的自己写出了代码。小专题

 

cogs930找第K小的数||1534K大数

题目大意:静态区间第K小的查询。

思路:裸裸的主席树模板题。

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

struct Node{

    Node *ch[2];

    int a,siz;

    Node (){ch[0]=ch[1]=NULL;siz=a=0;}

    void updata(){

        siz=a;

        if (ch[0]!=NULL) siz+=ch[0]->siz;

        if (ch[1]!=NULL) siz+=ch[1]->siz;

    }

}*null=new Node(),*root[100001]={NULL},q[2000001];

int a[100001]={0},a2[100001]={0},q_size=0;

void insert(Node *&y,Node *&x,int l,int r,int xx)

{

    int mid;

    if (x==NULL) x=null;

    y=&q[++q_size];

    *y=Node();

    if (l==r)

    {

        *y=*x;

        y->siz++;y->a++;

        return;

    }

    mid=(l+r)/2;

    if (xx<=a2[mid])

    {

        insert(y->ch[0],x->ch[0],l,mid,xx);

        y->ch[1]=x->ch[1];

        y->updata();

    }

    else

    {

        insert(y->ch[1],x->ch[1],mid+1,r,xx);

        y->ch[0]=x->ch[0];

        y->updata();

    }

}

void find(Node *&x2,Node *&x1,int l,int r,int k)

{

    int ss=0,mid;

    if (x2==NULL) x2=null;

    if (x1==NULL) x1=null;

    if (l==r)

    {

        printf("%d\n",a2[l]);

        return;

    }

    mid=(l+r)/2;

    if (x2->ch[0]!=NULL) ss+=x2->ch[0]->siz;

    if (x1->ch[0]!=NULL) ss-=x1->ch[0]->siz;

    if (ss>=k) find(x2->ch[0],x1->ch[0],l,mid,k);

    else find(x2->ch[1],x1->ch[1],mid+1,r,k-ss);

}

int main()

{

    freopen("kth.in","r",stdin);

    freopen("kth.out","w",stdout);

    

    int n,m,i,j,k,l,r;

    null->ch[0]=null;null->ch[1]=null;

    scanf("%d%d",&n,&m);

    for (i=1;i<=n;++i)

    {

        scanf("%d",&a[i]);

        a2[i]=a[i];

    }

    sort(a2+1,a2+n+1);

    int size;

    size=unique(a2+1,a2+n+1)-a2-1;

    for (i=1;i<=n;++i)

        insert(root[i],root[i-1],1,size,a[i]);

    for (i=1;i<=m;++i)

    {

        scanf("%d%d%d",&l,&r,&k);

        find(root[r],root[l-1],1,size,k);

    }

    

    fclose(stdin);

    fclose(stdout);

}
View Code

 

cogs257动态排名系统

题目大意:动态区间第K小的查询

思路:裸裸的动态主席。。。在原来的主席树外面套一个树状数组,然后就可以了。

#include<iostream>

#include<cstdio>

#include<algorithm>

#include<queue>

#include<iostream>

#include<cstring>

using namespace std;

struct use{

    int l,r,siz;

}tree[10000001]={0};

struct use1{

    int xx,yy,kk;

}qq[10001]={0};

int root[50001]={0},a[50001]={0},a2[60001]={0},q1[2000]={0},q2[2000]={0},tot=0,size,n;

char ch[10001];

int lowbit(int x){return x&-x;}

void build(int &x,int l,int r)

{

    int mid;

    tree[x=++tot].siz=0;

    if (l==r) return;

    mid=(l+r)/2;

    build(tree[x].l,l,mid);

    build(tree[x].r,mid+1,r);

}

void ins(int last,int &i,int l,int r,int x,int flag)

{

    tree[i=++tot].siz=tree[last].siz+flag;

    tree[i].l=tree[last].l;tree[i].r=tree[last].r;

    if (l==r) return;

    int mid=(l+r)/2;

    if (x<=mid) ins(tree[last].l,tree[i].l,l,mid,x,flag);

    else ins(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)) ins(root[i],root[i],1,size,x,flag);

}

int ask(int l,int r,int k)

{

    int ss=0,i,j,mid;

    if (l==r) return l;

    for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].l].siz;

    for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].l].siz;

    mid=(l+r)/2;

    if (ss>=k)

    {

        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)

{

    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];

    return ask(1,size,k);

}

int main()

{

    freopen("dynrank.in","r",stdin);

    freopen("dynrank.out","w",stdout);

    

    int m,i,j,d;

    scanf("%d",&d);

    while(d)

    {

    scanf("%d%d",&n,&m);

    tot=0;a2[0]=0;

    memset(tree,0,sizeof(tree));

    memset(root,0,sizeof(root));

    for (i=1;i<=n;++i) 

    {

      scanf("%d",&a[i]);

      ++a2[0];a2[a2[0]]=a[i];

    }

    for (i=1;i<=m;++i)

    {

        scanf("%*c%c%d%d",&ch[i],&qq[i].xx,&qq[i].yy);

        if (ch[i]=='Q') scanf("%d",&qq[i].kk);

        else a2[++a2[0]]=qq[i].yy;

    }

    sort(a2+1,a2+a2[0]+1);

    size=unique(a2+1,a2+a2[0]+1)-a2-1;

    build(root[0],1,size);

    for (i=1;i<=n;++i)

    {

        a[i]=upper_bound(a2+1,a2+size+1,a[i])-a2-1;

        bit_ins(i,a[i],1);

    }

    for (i=1;i<=m;++i)

    {

        if (ch[i]=='Q')

        {

            j=bit_ask(qq[i].xx-1,qq[i].yy,qq[i].kk);

            printf("%d\n",a2[j]);

        }

        else

        {

            bit_ins(qq[i].xx,a[qq[i].xx],-1);

            a[qq[i].xx]=upper_bound(a2+1,a2+size+1,qq[i].yy)-a2-1;

            bit_ins(qq[i].xx,a[qq[i].xx],1);

        }

    }

    --d;

    }

    

    fclose(stdin);

    fclose(stdout);

}
View Code

 

cogs1715||bzoj3295动态逆序对

题目大意:每次删除一个数,输出删除前逆序对的总个数。

思路:用的动态主席,倒着来做,ask略有不同,然后很开心的re了,之后NU刷cogs。。。MLE了一片。。。

#include<iostream>

#include<cstdio>

using namespace std;

struct use{

    int l,r,siz;

}tree[10000000];

int root[100001]={0},a[100001]={0},num[100001]={0},a2[100001]={0},del[50001]={0},q1[2000]={0},q2[2000]={0},

    cc[100001]={0},tot=0,n;

long long ansi[50001]={0};

int lowbit(int x) {return x&(-x);}

int work(int l,int r)

{

    int mid,ans=0,i,j;

    if (l==r) return ans;

    mid=(l+r)/2;

    ans+=work(l,mid)+work(mid+1,r);

    cc[0]=0;i=l;j=mid+1;

    while(i<=mid&&j<=r)

    {

        if (a2[i]<a2[j])

        {

            cc[++cc[0]]=a2[i];++i;

        }

        else

        {

            cc[++cc[0]]=a2[j];++j;

            ans+=mid-i+1;

        }

    }

    for (;i<=mid;++i) cc[++cc[0]]=a2[i];

    for (;j<=r;++j) cc[++cc[0]]=a2[j];

    for (i=l;i<=r;++i) a2[i]=cc[i-l+1];

    return ans;

}

void build(int &x,int l,int r)

{

    int mid;

    tree[x=++tot].siz=0;

    if (l==r) return;

    mid=(l+r)/2;

    build(tree[x].l,l,mid);

    build(tree[x].r,mid+1,r);

}

void ins(int last,int &i,int l,int r,int x,int flag)

{

    int mid;

    tree[i=++tot].siz=tree[last].siz+flag;

    tree[i].l=tree[last].l;tree[i].r=tree[last].r;

    if (l==r) return;

    mid=(l+r)/2;

    if (x<=mid) ins(tree[last].l,tree[i].l,l,mid,x,flag);

    else ins(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)) ins(root[i],root[i],1,n,x,flag);

}

long long ask(int l,int r,int x,int flag)

{

    long long ss=0;

    int mid,i;

    if (l==r) return 0;

    mid=(l+r)/2;

    if (flag==0)

    {

        ss=0;

        for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].l].siz;

        for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].l].siz;

        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 ask(l,mid,x,flag);

        }

        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+ask(mid+1,r,x,flag);

        }

    }

    else

    {

        ss=0;

        for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].r].siz;

        for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].r].siz;

        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 ss+ask(l,mid,x,flag);

        }

        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,x,flag);

        }

    }

}

long long bit_ask(int l,int r,int x,int flag)

{

    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];

    return ask(1,n,x,flag);

}

int main()

{

    freopen("inverse.in","r",stdin);

    freopen("inverse.out","w",stdout);

    

    int m,i,j,k;

    long long ans=0;

    scanf("%d%d",&n,&m);

    for (i=1;i<=n;++i) 

    {

       scanf("%d",&a[i]);

       num[a[i]]=i;

    }

    for (i=m;i>=1;--i)

    {

        scanf("%d",&del[i]);

        a[num[del[i]]]=0;

    }

    build(root[0],1,n);

    for (i=1;i<=n;++i)

        if (a[i])

        {

           a2[++a2[0]]=a[i];

           bit_ins(i,a[i],1);

        }

    ans=work(1,a2[0]);

    for (i=1;i<=m;++i)

    {

        k=del[i];j=num[k];a[j]=k;

        bit_ins(j,k,1);

        if (j>1) ans+=bit_ask(0,j-1,k,1);

        if (j<n) ans+=bit_ask(j,n,k,0);

        ansi[i]=ans;

    }

    for (i=m;i>=1;--i) printf("%I64d\n",ansi[i]);

    

    fclose(stdin);

    fclose(stdout);

}
80分code

终于发现re的原因了,其实之前写的主席树一直有一些漏洞,每次插入一个点的时候都会新建很多节点,其实有的节点是可以直接用原来的就可以了。

#include<iostream>

#include<cstdio>

using namespace std;

struct use{

    int l,r,siz;

}tree[10000000];

int root[100001]={0},a[100001]={0},num[100001]={0},a2[100001]={0},del[50001]={0},q1[2000]={0},q2[2000]={0},

    cc[100001]={0},tot=0,n;

long long ansi[50001]={0};

int lowbit(int x) {return x&(-x);}

int work(int l,int r)

{

    int mid,ans=0,i,j;

    if (l==r) return ans;

    mid=(l+r)/2;

    ans+=work(l,mid)+work(mid+1,r);

    cc[0]=0;i=l;j=mid+1;

    while(i<=mid&&j<=r)

    {

        if (a2[i]<a2[j])

        {

            cc[++cc[0]]=a2[i];++i;

        }

        else

        {

            cc[++cc[0]]=a2[j];++j;

            ans+=mid-i+1;

        }

    }

    for (;i<=mid;++i) cc[++cc[0]]=a2[i];

    for (;j<=r;++j) cc[++cc[0]]=a2[j];

    for (i=l;i<=r;++i) a2[i]=cc[i-l+1];

    return ans;

}

void build(int &x,int l,int r)

{

    int mid;

    tree[x=++tot].siz=0;

    if (l==r) return;

    mid=(l+r)/2;

    build(tree[x].l,l,mid);

    build(tree[x].r,mid+1,r);

}

void ins(int last,int &i,int l,int r,int x,int flag)

{

    int mid;

    if (!i) i=++tot;

    tree[i].siz=tree[last].siz+flag;

    tree[i].l=tree[last].l;tree[i].r=tree[last].r;

    if (l==r) return;

    mid=(l+r)/2;

    if (x<=mid) ins(tree[last].l,tree[i].l,l,mid,x,flag);

    else ins(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)) ins(root[i],root[i],1,n,x,flag);

}

long long ask(int l,int r,int x,int flag)

{

    long long ss=0;

    int mid,i;

    if (l==r) return 0;

    mid=(l+r)/2;

    if (flag==0)

    {

        ss=0;

        for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].l].siz;

        for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].l].siz;

        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 ask(l,mid,x,flag);

        }

        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+ask(mid+1,r,x,flag);

        }

    }

    else

    {

        ss=0;

        for (i=1;i<=q2[0];++i) ss+=tree[tree[q2[i]].r].siz;

        for (i=1;i<=q1[0];++i) ss-=tree[tree[q1[i]].r].siz;

        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 ss+ask(l,mid,x,flag);

        }

        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,x,flag);

        }

    }

}

long long bit_ask(int l,int r,int x,int flag)

{

    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];

    return ask(1,n,x,flag);

}

int main()

{

    freopen("inverse.in","r",stdin);

    freopen("inverse.out","w",stdout);

    

    int m,i,j,k;

    long long ans=0;

    scanf("%d%d",&n,&m);

    for (i=1;i<=n;++i) 

    {

       scanf("%d",&a[i]);

       num[a[i]]=i;

    }

    for (i=m;i>=1;--i)

    {

        scanf("%d",&del[i]);

        a[num[del[i]]]=0;

    }

    build(root[0],1,n);

    for (i=1;i<=n;++i)

        if (a[i])

        {

           a2[++a2[0]]=a[i];

           bit_ins(i,a[i],1);

        }

    ans=work(1,a2[0]);

    for (i=1;i<=m;++i)

    {

        k=del[i];j=num[k];a[j]=k;

        bit_ins(j,k,1);

        if (j>1) ans+=bit_ask(0,j-1,k,1);

        if (j<n) ans+=bit_ask(j,n,k,0);

        ansi[i]=ans;

    }

    for (i=m;i>=1;--i) printf("%lld\n",ansi[i]);

    

    fclose(stdin);

    fclose(stdout);

}
AC code

 

其他树套树问题

cogs1345 K大数查询

题目大意:有n个连续的区间,每个区间可以放多个数,区间修改,查找区间内的第K大。

思路:树状数组(权值)套线段树(位置)。因为不会写其他的树套树,也不会树状数组的区间修改,于是只能写成这样了。插入的时候log^2n,查询的时候二分一下log^3n,然后就会发现自己T了。因为自己用了pushdown,然后就会开很多没有用的点,也会一遍一遍的访问他们。那我们只能不用pushdown,然后传入一个变量fadel,然后更新一下就可以了!!!那么这里的siz保存的就是这个节点及它下面的元素个数,并没有保存它上方的!!!因为这里是第K大,而我只会树状数组第K小,所以又用了一棵线段树来维护区间元素的个数,以转化成第K小。

 

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

struct use{

    int l,r,siz,del;

}tree[20000000]={0};

int tot=0,wotr[200000]={0},delta[200000]={0},root[50001]={0},n,size=0;

int lowbit(int x){return x&(-x);}

void paint(int i,int x,int l,int r)

{

    delta[i]+=x;wotr[i]+=x*(r-l+1);

}

void pushdown(int i,int l,int r)

{

    int mid;

    mid=(l+r)/2;

    paint(i*2,delta[i],l,mid);

    paint(i*2+1,delta[i],mid+1,r);

    delta[i]=0;

}

void insert(int i,int l,int r,int ll,int rr)

{

    int mid;

    if (ll<=l&&r<=rr)

    {

        paint(i,1,l,r);

        return;

    }

    mid=(l+r)/2;

    pushdown(i,l,r);

    if  (ll<=mid) insert(i*2,l,mid,ll,rr);

    if (rr>mid) insert(i*2+1,mid+1,r,ll,rr);

    wotr[i]=wotr[i*2]+wotr[i*2+1];

}

int work(int i,int l,int r,int ll,int rr)

{

    int mid,sum=0;

    if (ll<=l&&r<=rr) return wotr[i];

    pushdown(i,l,r);mid=(l+r)/2;

    if (ll<=mid) sum+=work(i*2,l,mid,ll,rr);

    if (rr>mid) sum+=work(i*2+1,mid+1,r,ll,rr);

    return sum;

}

void ins(int &i,int l,int r,int ll,int rr,int x,int fadel)

{

    int mid;

    if (i==0) i=++tot;

    if (ll<=l&&r<=rr)

    {

        ++tree[i].del;tree[i].siz=(tree[i].l==0?0:tree[tree[i].l].siz)+(tree[i].r==0?0:tree[tree[i].r].siz)+tree[i].del*(r-l+1);

        return;

    }

    mid=(l+r)/2;

    if (ll<=mid) ins(tree[i].l,l,mid,ll,rr,x,fadel+tree[i].del);

    if (rr>mid) ins(tree[i].r,mid+1,r,ll,rr,x,fadel+tree[i].del);

    tree[i].siz=(tree[i].l==0?0:tree[tree[i].l].siz)+(tree[i].r==0?0:tree[tree[i].r].siz)+tree[i].del*(r-l+1);

}

void bit_ins(int x,int l,int r)

{

    for (;x<=n;x+=lowbit(x)) ins(root[x],1,n,l,r,1,0);

}

int ask(int i,int l,int r,int ll,int rr,int fadel)

{

    int mid,sum=0;

    if (!i) return (fadel*(min(r,rr)-max(l,ll)+1));

    if (ll<=l&&r<=rr) return tree[i].siz+fadel*(r-l+1);

    mid=(l+r)/2;

    if (ll<=mid) sum+=ask(tree[i].l,l,mid,ll,rr,tree[i].del+fadel);

    if (rr>mid) sum+=ask(tree[i].r,mid+1,r,ll,rr,tree[i].del+fadel);

    return sum;

}

int bit_ask(int x,int ll,int rr)

{

    int sum=0;

    for (;x>0;x-=lowbit(x)) sum+=ask(root[x],1,n,ll,rr,0);

    return sum;

}

int to_ask(int l,int r,int ll,int rr,int k)

{

    int mid,sum=0,ans;

    if (l==r) return l;

    mid=(l+r)/2;

    sum=bit_ask(mid,ll,rr);

    if (k<=sum) ans=to_ask(l,mid,ll,rr,k);

    else ans=to_ask(mid+1,r,ll,rr,k);

    return ans;

}

int main()

{

    freopen("zjoi13_sequence.in","r",stdin);

    freopen("zjoi13_sequence.out","w",stdout);

    

    int m,i,j,kind,aa,bb,cc;

    scanf("%d%d",&n,&m);

    for (i=1;i<=m;++i)

    {

        scanf("%d%d%d%d",&kind,&aa,&bb,&cc);

        if (kind==1)

        {

            bit_ins(cc,aa,bb);

            insert(1,1,n,aa,bb);

        }

        else

        {

            j=work(1,1,n,aa,bb);

            cc=j-cc+1;

            j=to_ask(1,n,aa,bb,cc);

            printf("%d\n",j);

        }

    }

    

    fclose(stdin);

    fclose(stdout);

}
View Code

 

你可能感兴趣的:(树)