我想要打一个主席树

这里提供了静态主席树及动态主席树(树状数组套主席树)的模板。
分别应用于静态区间第k小及动态区间第k小。
静态:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
using namespace std;
char *p1,*p2,buf[1<<20]; 

#define GC (p1==p2&&(p1=buf,p2=buf+fread(buf,1,1<<20,stdin),p1==p2)?0:(*(p1++)))
//#define GC getchar()
inline int in()
{
    int ans;
    char t,k;
    while(((t=GC)!='-'&&(t>'9'||t<'0')));
    k=(t=='-');
    ans=k?0:(t-'0');
    while((t=GC)>='0'&&t<='9')ans=ans*10+t-'0';
    return k?-ans:ans;
}
const int maxn=100010;
struct node{
    int ls,rs;
    int sum;
};
int root[maxn];
struct tree{
    node t[maxn<<5];
    int tot=0;
    inline void build(int &rt,int l,int r)
    {
        rt=++tot;
        t[rt].sum=0;
        if(l==r)return;
        int mid=((l+r)>>1);
        build(t[rt].ls,l,mid);
        build(t[rt].rs,mid+1,r);
    }
    int updata(int x,int p,int l,int r){
        int rt=++tot;
        t[rt].ls=t[p].ls;
        t[rt].rs=t[p].rs;
        t[rt].sum=t[p].sum+1;
        if(l==r)return rt;
        int mid=((l+r)>>1);
        if(mid>=x)t[rt].ls=updata(x,t[rt].ls,l,mid);
        else t[rt].rs=updata(x,t[rt].rs,mid+1,r);
        return rt;
    }
    int gs(int x,int y,int l,int r,int k){
        int mid=((l+r)>>1);
        int tmp=t[t[y].ls].sum-t[t[x].ls].sum;
        if(l==r)return l;
        if(k<=tmp)return gs(t[x].ls,t[y].ls,l,mid,k);
        else return gs(t[x].rs,t[y].rs,mid+1,r,k-tmp);
    }
}tr;
int n,m;
int a[maxn],b[maxn];
int main()
{
    n=in();m=in();
    int i,j;
    for(i=1;i<=n;i++){
        a[i]=in();
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    int bs=unique(b+1,b+n+1)-b-1;
    tr.build(root[0],1,bs);
    for(i=1;i<=n;i++)
    {
        int pos=lower_bound(b+1,b+bs+1,a[i])-b;
        root[i]=tr.updata(pos,root[i-1],1,bs);
    }
    for(i=1;i<=m;i++)
    {
        int l,r,k;
        l=in();r=in();k=in();
        printf("%d\n",b[tr.gs(root[l-1],root[r],1,bs,k)]);
    }
    return 0;
}

?
动态
注:动态的主席树空间一定要开大,不然RE调一天都调不出来

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline int lowbit(int x){return x&(-x);}
struct node{
    int sum,ls,rs;
};
const int maxn=500100;
int n,m;
int root1[maxn<<2];
int root[maxn<<2];
int a[maxn<<2],b[maxn<<2],bs;
int tl[maxn<<2],tr[maxn<<2];
struct tree{
    node sum[maxn<<6];
    int tot=0;
    void pushup(int p)
    {
        sum[p].sum=sum[sum[p].ls].sum+sum[sum[p].rs].sum;
    }
    void build(int &p,int l,int r)
    {
        p=++tot;
        if(l==r)return;
        int mid=((l+r)>>1);
        build(sum[p].ls,l,mid);
        build(sum[p].rs,mid+1,r);
//      pushup(p);
    }
    int ins(int x,int p,int l,int r,int k)
    {
        int p1=++tot;
        sum[p1].ls=sum[p].ls;
        sum[p1].rs=sum[p].rs;
        sum[p1].sum=sum[p].sum+k;
        if(l==r){
            return p1;
        }
        int mid=((l+r)>>1);
        if(x<=mid)sum[p1].ls=ins(x,sum[p].ls,l,mid,k);
        else sum[p1].rs=ins(x,sum[p].rs,mid+1,r,k);
//      pushup(p1);
        return p1;
    }
    void add(int x,int k)
    {
        int pos=lower_bound(b+1,b+bs+1,a[x])-b;
        while(x<=n){
            root[x]=ins(pos,root[x],1,bs,k);
            x+=lowbit(x);
        }
    }
    int r_gs(int x,bool f)
    {
        int res=0;
        while(x){
            if(f)res+=sum[sum[tr[x]].ls].sum;
            else res+=sum[sum[tl[x]].ls].sum;
            x-=lowbit(x);
        }
        return res;
    }
    int gs(int x,int y,int rx,int ry,int l,int r,int k)
    {
        if(l==r)return l;
        int mid=((l+r)>>1);
        int res=r_gs(y,1)-r_gs(x,0)+sum[sum[ry].ls].sum-sum[sum[rx].ls].sum;
        if(k<=res){
            int i;
            for(i=y;i;i-=lowbit(i))tr[i]=sum[tr[i]].ls;
            for(i=x;i;i-=lowbit(i))tl[i]=sum[tl[i]].ls;
            return gs(x,y,sum[rx].ls,sum[ry].ls,l,mid,k);
        }
        else {
            int i;
            for(i=y;i;i-=lowbit(i))tr[i]=sum[tr[i]].rs;
            for(i=x;i;i-=lowbit(i))tl[i]=sum[tl[i]].rs;
            return gs(x,y,sum[rx].rs,sum[ry].rs,mid+1,r,k-res);
        }
    }
}st;
struct actt{
    int x,y,k;
    bool ch;
}g[maxn<<2];
int main()
{
    int i,j;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=a[i];
        bs+=1;
    }
    for(i=1;i<=m;i++)
    {
        char cc;
        cin>>cc>>g[i].x;
        if(cc=='Q')cin>>g[i].y>>g[i].k,g[i].ch=1;
        else cin>>g[i].y,b[++bs]=g[i].y;
    }
    sort(b+1,b+bs+1);
    int tmp=unique(b+1,b+bs+1)-b-1;
    bs=tmp;
    b[0]=-233;
    st.build(root1[0],1,bs);
    for(i=1;i<=n;i++)root1[i]=st.ins(lower_bound(b+1,b+bs+1,a[i])-b,root1[i-1],1,bs,1);
    for(i=1;i<=n;i++)root[i]=root1[0];
    for(i=1;i<=m;i++)
    {
        if(g[i].ch){
            for(j=g[i].y;j;j-=lowbit(j))tr[j]=root[j];
            for(j=g[i].x-1;j;j-=lowbit(j))tl[j]=root[j];
            printf("%d\n",b[st.gs(g[i].x-1,g[i].y,root1[g[i].x-1],root1[g[i].y],1,bs,g[i].k)]);
        }
        else{
            st.add(g[i].x,-1);
            a[g[i].x]=g[i].y;
            st.add(g[i].x,1);
        }
    }
    return st.tot;
}

思路好想码量巨大警告

原文地址:https://www.cnblogs.com/cooper233/p/12037924.html

时间: 2024-10-13 12:19:22

我想要打一个主席树的相关文章

少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小

少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小 有一道题(BZOJ 1901)是这样的:n个数,m个询问,询问有两种:修改某个数/询问区间第k小. 不带修改的区间第k小用主席树很好写,不会的同学可以看一下这个. 加上修改怎么做呢?我们可以用数学老师成天讲的类比思想: 可以发现,不修改的区间k小问题中,每加入一个原序列中的数,对应的主席树在上一个的基础上进行修改,而查询的时候用右端点主席树减去左端点左边的主席树.这样的操作就像是维护前缀和:每次加入一个元素的时候,sum[i] =

【bzoj4408】[Fjoi 2016]神秘数 主席树

题目描述 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1+13 = 1+1+14 = 45 = 4+16 = 4+1+17 = 4+1+1+18无法表示为集合S的子集的和,故集合S的神秘数为8.现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间[l,r](l<=r),求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘数. 输入 第一行一个整数n,表示数字个数.第二行n个整数,从1编

对主席树的理解以及使用

引入 一个长度为\(n\)的数组,有\(m\)次查询,每次查询区间\([l,r]\)内第\(k\)小的元素. 如果使用暴力,肯定不可以 使用线段树?可是我只会查询区间最值啊. 那么我们把问题再次简化一下,查询\([1,n]\)第\(k\)小的元素,要求使用线段树来实现. 权值线段树 为了解决这个问题,我们引入一个名词:权值线段树.那么权值线段树是如何解决上面那个问题的呢? 首先,我们对数组进行离散化处理,离散成为\([1,n]\),然后我们建一颗线段树,线段树的节点存放的即为对应区间的数的个数.

HDU 2665 Kth number (主席树)

题意:给定一个序列,求给定区间的第 k 小的值. 析:就是一个主席树的裸板. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring&g

【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA

[BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组

带修改的主席树

普通主席树认为是前缀套线段树,那么这就是树状数组套线段树 前缀区间由原来的一个前缀一个线段树变成BIT组成的几棵线段树一起 每个线段树维护的还是离散排序后的数列 每个节点也相当于一个主席树,我觉得更像是线段树,但是修改的时候用到了主席树的方法,就是在原来的基础上修改(只不过这些原来的都不保存) add操作要修改一些主席树 sum操作要加一些主席树的区间和 外层的BIT是为了处理询问区间,内层是为了找k值 kth时候要把用到的主席树提出了,每个都往左往右 代码(未提交过) // // main.c

#LOJ2564 SDOI2018 原题识别 主席树

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/9057297.html 原题链接: 今天考试考了前天的SDOI考题 天啊我菜爆,只有T2拿了30分 然后考试后半程一直在打T1 觉得考试思路很有意思,于是就顺着打下来了 个人感觉这个是$O(nlogn^{2})$的,但是在loj上我比claris的程序快了1s多,只不过编程复杂度不止翻倍啊…… 下面介绍一下我的解法 其实最早启发我的是链上的部分分 定义$pre_{i}$为i前面最近的和i同色的点的下标,我们把

luogu P2137 Gty的妹子树(分块,主席树)

询问的化我们可以建主席树.然后修改?,树套树...,最后插入?炸了. 所以我们对操作进行分块. 我们先对整棵树建一个主席树.修改,插入我们先记录下来.然后询问的时候先对主席树查询,然后暴力遍历我们记录下来的修改插入操作.每\(\sqrt{m}\)次操作后我们重新构建一个主席树.这样我们保证了重建主席树和询问的总复杂度为\(O(nlogn\sqrt{m})\)然后就把这道题解决了. 有一个难办的事就是如何记录修改和插入的操作.可以使每次询问的时候我们可以知道修改和插入是否在\(u\)的子树中以便我

主席树(入门篇)

主席树 write by BigYellowDog 前置知识:线段树.离散化.前缀和.最好还有Splay 主席树是什么? 首先跟你说说这名字的由来.据说,是一位叫fotile主席的大大在写一道题时因为不会划分树就临时yy出一个算法,于是,这算法就这么诞生了.(这就是大佬吗Orz-) 主席树全称叫可持续化线段树,好复杂.其实就是可以重复利用信息的线段树,从而减小空间和时间的开销.举个例子,为了做到重复利用信息,它时这个样子的: 去孤独·粲泽博客找的的图片,ta讲的也特别好辣,推荐大家去看看 看到没