主席树

8 篇文章 0 订阅
3 篇文章 0 订阅

 主席树


好神的数据结构,不过挺好写的。。

POJ 2104 K-th number

题目大意:
     对一静态序列,每次询问[l,r]中第k大d

主席树模板题

贴代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#define M 100010
using namespace std;


struct Node{
    int l,r,s;
}a[M*50];

int id[M],d[M],cnt,key;
void update(int l,int r,int &pos)
{
    a[++cnt]=a[pos];
    pos=cnt;
    ++a[pos].s;
    if(l==r)
    return ;
    int m=(l+r)/2;
    if(key<=m)
    update(l,m,a[pos].l);
    else
    update(m+1,r,a[pos].r);
}

int query(int l,int r,int x,int y,int k)
{
    if(l==r)
    return l;
    int mid=(l+r)/2,s=a[a[y].l].s-a[a[x].l].s;
    if(k<=s)
    return query(l,mid,a[x].l,a[y].l,k);
    else
    return query(mid+1,r,a[x].r,a[y].r,k-s);
}
bool cmp(int x,int y)
{
    return d[x]<d[y];

}
int n,m;
int b[M];
int root[M];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d",&d[i]),id[i]=i;
    sort(id+1,id+n+1,cmp);
    for(int i=1;i<=n;i++)
    b[id[i]]=i;
    for(int i=1;i<=n;i++)
    {
        root[i]=root[i-1];
        key=b[i];
        update(1,n,root[i]);
    }
    int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&key);
        int td=query(1,n,root[x-1],root[y],key);
        printf("%d\n",d[id[td]]);

    }
    return 0;
}


HDU 4417 Super Mario

题目大意:

对于一静态序列,询问[l,r]中小于x的个数

这题有树状数组解法,不过我用二分+主席树过了,
(跑得也很快,BIT 200+ms   二分+主席树 500+ms

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define M  100010

using namespace std;

int d[M],b[M],id[M],root[M],cnt,key,T,n,m;
struct Node{

    int l,r,s;
}a[M*30];


bool cmp (int x,int y)
{
    return d[x]<d[y];
}
void update(int &t,int l,int r)
{
    a[++cnt]=a[t];
    t=cnt;
    ++a[t].s;
    if(l==r)
        return ;
    int mid=(l+r)/2;
    if(key<=mid)
        update(a[t].l,l,mid);
    else
        update(a[t].r,mid+1,r);
}
int query(int l,int r,int x,int y,int k)
{
    if(l==r)
        return l;
    int mid=(l+r)/2,s=a[a[y].l].s-a[a[x].l].s;
    if(k<=s)
    return query(l,mid,a[x].l,a[y].l,k);
    else
    return query(mid+1,r,a[x].r,a[y].r,k-s);
}


int main()
{
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        scanf("%d%d",&n,&m);
        printf("Case %d:\n",cas);
        for(int i=1;i<=n;i++)
            scanf("%d",&d[i]),id[i]=i;
        sort(id+1,id+n+1,cmp);
        for(int i=1;i<=n;i++)
            b[id[i]]=i;
        for(int i=1;i<=n;i++)
        {
            root[i]=root[i-1];
            key=b[i];
            update(root[i],1,n);
        }
        for(int i=1,x,y;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&key);
            x++,y++;
            if(d[id[query(1,n,root[x-1],root[y],y-x+1)]]<=key)
            {
                printf("%d\n",y-x+1);

            }
            else
                if(d[id[query(1,n,root[x-1],root[y],1)]]>key)
            {

                printf("0\n");
            }
            else
            {
                int l=0,r=y-x+1;
                int ans=0,mid;
                while(l<=r)
                {
                    int mid=(l+r)/2;
                    if(d[id[query(1,n,root[x-1],root[y],mid)]]<=key)
                        l=mid+1,ans=mid;
                    else
                        r=mid-1;
                }
                printf("%d\n",ans);
            }
        }
    }
    return 0;


}


SPOJ COT Count on a tree

s=s(lson[u])+s(lson[v])-2*s(lson[lca])
记住如果lca 在[l,mid] 中 s要+1

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#define M 100005

using namespace std;

int g[M];
struct Edge
{
    int nxt,v;
} e[M*2];

struct Node
{
    int l,r,s;

} a[M*20];
vector<pair<int ,int > > q[M];
int cnt,num,key,n,m;
int p[M],fa[M],id[M],d[M],b[M],root[M];
int from[M],to[M],val[M];
void add(int u,int v)
{
    e[++cnt].nxt=g[u],e[cnt].v=v,g[u]=cnt;
    e[++cnt].nxt=g[v],e[cnt].v=u,g[v]=cnt;
}

void update(int &t,int l,int r)
{
    a[++num]=a[t];
    t=num;
    ++a[t].s;
    if(l==r)
        return ;
    int mid=(l+r)/2;
    if(key<=mid)
        update(a[t].l,l,mid);
    else
        update(a[t].r,mid+1,r);
}

int ifind(int x)
{
    return p[x] == x  ?  x : p[x]=ifind(p[x]);
}
bool vis[M];
int lca[M];

void dfs(int x)
{
   // cout<<x<<endl;
    p[x]=x;
    key=b[x];
    root[x]=root[fa[x]];
    update(root[x],1,n);
    for(int i=g[x]; i; i=e[i].nxt)
        if(e[i].v!=fa[x])
        {
            //cout<<e[i].v<<endl;
            fa[e[i].v]=x;
            dfs(e[i].v);
            p[e[i].v]=x;
        }
    vis[x]=1;
    int t=q[x].size();
    for(int i=0; i<t; ++i)
        if(vis[q[x][i].first])
        {
            lca[q[x][i].second]=ifind(q[x][i].first);
        }
}

bool cmp(int x,int y)
{
    return d[x]<d[y];


}

int getans(int l,int r,int x,int y,int f,int k)
{
    if(l==r)
        return l;
    int mid=(l+r)/2,s=a[a[x].l].s+a[a[y].l].s-(a[a[f].l].s<<1);
    if(b[key]>=l && b[key]<=mid)
        ++s;
    if(k<=s)
        return getans(l,mid,a[x].l,a[y].l,a[f].l,k);
    else
        return getans(mid+1,r,a[x].r,a[y].r,a[f].r,k-s);
}


int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
        scanf("%d",&d[i]),id[i]=i;
    sort(id+1,id+n+1,cmp);
    for(int i=1; i<=n; i++)
        b[id[i]]=i;
    for(int i=1,x,y; i<n; i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1; i<=m; ++i)
    {
        scanf("%d%d%d",&from[i],&to[i],&val[i]);
        q[from[i]].push_back(pair<int, int> (to[i], i));
        q[to[i]].push_back(pair<int, int> (from[i], i));
    }
    dfs(1);
    for(int i=1; i<=m; ++i)
    {
        if(from[i]==to[i])
        {
            printf("%d\n", d[from[i]]);
            continue;
        }
        key=lca[i];
        printf("%d\n", d[id[getans(1, n, root[from[i]], root[to[i]], root[key], val[i])]]); //被root[ff]坑了一早上,写成了ff。唉
    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值