主席树-poj2104

邝斌的模板就是好用一打上去就对了,对树状数组也有了初步的了解,主席树相当于N+1课线段树,每颗线段树维护的是数组元素的前缀和或者后缀和,根据映射关系,返回相应的下标,然后取的其值,好吧,初步就是这样,但为什么,邝斌的模板过了,我自己手敲的结构体类型的就 错了,心累,留着吧,以后彻底弄清楚了我再回来解决你。真的服气。

AC代码(邝斌神代码后缀和):

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define siz 100005
#define LL int

using namespace std;
int n,q,tot,m;
int a[siz],t[siz];
int T[siz],lson[siz*30],rson[siz*30],c[siz*30];

void Init_hash(){
    for(int i=1;i<=n;i++){
        t[i]=a[i];
    }
    sort(t+1,t+1+n);
    m=unique(t+1,t+1+n)-t-1;
}
int build(int l,int r){
    int root=tot++;
    c[root]=0;
    if(l!=r){
        int mid=(l+r)>>1;
        lson[root]=build(l,mid);
        rson[root]=build(mid+1,r);
    }
    return root;
}
int hash(int x){
    return lower_bound(t+1,t+1+m,x)-t;
}
int updata(int root,int pos,int val){
    int newroot = tot++,tmp=newroot;
    c[newroot] = c[root] + val;
    int l=1,r=m;
    while(l<r){
        int mid = (l+r)>>1;
        if(pos <= mid){
            lson[newroot] = tot++;rson[newroot] = rson[root];
            newroot= lson[newroot];root=lson[root];
            r=mid;
        }
        else{
            rson[newroot]= tot++;lson[newroot]=lson[root];
            newroot=rson[newroot];root=rson[root];
            l=mid+1;
        }
        c[newroot] = c[root]+val;
    }
    return tmp;
}
int query(int left_root,int right_root,int k){
    int l=1,r=m;
    while(l<r){
        int mid=(l+r)>>1;
        if(c[lson[left_root]]-c[lson[right_root]]>=k){
            r=mid;
            left_root=lson[left_root];
            right_root=lson[right_root];
        }
        else{
            l=mid+1;
            k-=c[lson[left_root]]-c[lson[right_root]];
            left_root=rson[left_root];
            right_root=rson[right_root];
        }
    }
    return l;
}

void solve(){
    tot=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    Init_hash();
    //for(int i=1;i<=n;i++){
       // cout<<t[i]<<"^^^^"<<endl;
   // }
   // cout<<m<<"----"<<endl;
    T[n+1]=build(1,m);
    //cout<<tot<<" "<<m<<endl;
    for(int i=n;i>=1;i--){
        int pos =hash(a[i]);
       // cout<<pos<<endl;
        T[i]= updata(T[i+1],pos,1);
    }
    while(q--){
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        int index=query(T[l],T[r+1],k);
        int ans=t[index];
        printf("%d\n",ans);
    }
}
int main()
{
    while(~scanf("%d %d",&n,&q)){
        solve();
    }
    return 0;
}

自己很二的过不了的代码:(错误已找到,build里的l我打成了一个1,所以就耗了我一个上午的时间?这么多树,都不好调试。。服了)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define siz 100005

using namespace std;
struct node{
    int ls,rs;
    int c;
}rt[siz*30];
int arr[siz],trr[siz],T[siz];
int n,q,tot,m;
void Init_hash(){
    for(int i=1;i<=n;i++){
        trr[i]=arr[i];
    }
    sort(trr+1,trr+n+1);
    m=unique(trr+1,trr+1+n)-trr-1;
}
int build(int l,int r){
    int root=tot++;
    rt[root].c=0;
    if(l!=r){
        int mid=(l+r)>>1;
        rt[root].ls=build(1,mid);
        rt[root].rs=build(mid+1,r);
    }
    return root;
}
int hashx(int x){
    return lower_bound(trr+1,trr+1+m,x)-trr;
}
int updata(int root,int pos,int val){
    int newroot=tot++,tmp=newroot;
    rt[newroot].c=rt[root].c+val;
    int l=1,r=m;
    while(l<r){
        int mid=(l+r)>>1;
        if(pos<=mid){
            rt[newroot].ls=tot++;
            rt[newroot].rs=rt[root].rs;
            newroot=rt[newroot].ls;
            root=rt[root].ls;
            //rt[newroot].c
            r=mid;
        }
        else{
            rt[newroot].rs=tot++;
            rt[newroot].ls=rt[root].ls;
            newroot=rt[newroot].rs;
            root=rt[root].rs;
            l=mid+1;
        }
        rt[newroot].c=rt[root].c+val;
    }
    return tmp;
}
int query(int left_root,int right_root,int k){
    int l=1,r=m;
    while(l<r){
        int mid=(l+r)>>1;
        //int le=
        if((rt[rt[left_root].ls].c-rt[rt[right_root].ls].c)>=k){
            r=mid;
            left_root=rt[left_root].ls;
            right_root=rt[right_root].ls;
        }
        else{
            l=mid+1;
            k-=(rt[rt[left_root].ls].c-rt[rt[right_root].ls].c);
            left_root=rt[left_root].rs;
            right_root=rt[right_root].rs;
        }
    }
    return l;
}
int main()
{
  int cas;
  /// scanf("%d",&cas);
  // while(cas--){

       while(~scanf("%d %d",&n,&q)){
         tot=0;
         memset(T,0,sizeof(T));
         memset(rt,0,sizeof(rt));
        for(int i=1;i<=n;i++){
            scanf("%d",&arr[i]);
        }
        //cout<<"&&"<<endl;
        Init_hash();
       // cout<<1<<endl;
        T[n+1]=build(1,m);
        for(int i=n;i>=1;i--){
            int pos=hashx(arr[i]);
            T[i]=updata(T[i+1],pos,1);
        }
      /*  for(int i=1;i<=n;i++){
            printf("%d ",rt[T[i]].c);
        }
        cout<<endl;*/
        //cout<<1<<endl;
        while(q--){
            int l,r,k;
            scanf("%d %d %d",&l,&r,&k);
            int inde=query(T[l],T[r+1],k);
            int ans=trr[inde];
            printf("%d\n",ans);
        }
    }
    return 0;
}

感觉没啥区别呀,就是过不了,就是过不了,真的气!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值