树套树-线段树套平衡树

树套树留坑

线段树套平衡树:

二逼平衡树

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<map>
#include<bitset>
#pragma GCC optimize(2)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
const int N=6000000,inf=2147483647;
int n,m,maxn,a[N+10];
int tot,rt[N+10],sz[N+10],rec[N+10],v[N+10],fa[N+10],ch[N+10][2];
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
//----------------------Splay--------------------------
inline int ident(int x){return ch[fa[x]][0]==x?0:1;}
inline void splay_clear(int x){fa[x]=ch[x][0]=ch[x][1]=sz[x]=rec[x]=v[x]=0;}
inline void splay_pushup(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+rec[x];}
inline void rotate(int x)
{
    int Y=fa[x],R=fa[Y],Yson=ident(x),Rson=ident(Y);
    if(R)ch[R][Rson]=x;
    if(ch[x][Yson^1]) fa[ch[x][Yson^1]]=Y;
    ch[Y][Yson]=ch[x][Yson^1];
    ch[x][Yson^1]=Y;
    fa[Y]=x;
    fa[x]=R;
    splay_pushup(Y),splay_pushup(x);
}
inline void splay(int &rt,int x,int to)
{
    to=fa[to];
    while(fa[x]!=to)
    {
        int y=fa[x];
        if(fa[y]==to) rotate(x);
        else if(ident(x)==ident(y)) rotate(y),rotate(x);
        else rotate(x),rotate(x);
    }
    if(!to) rt=x;
}
inline void splay_insert(int &rt,int d)
{
    if(!rt)
    {
        rt=++tot;
        v[rt]=d;
        sz[rt]=rec[rt]=1;
        fa[rt]=ch[rt][0]=ch[rt][1]=0;
        return;
    }
    int x=rt;
    while(1)
    {
        sz[x]++;
        if(v[x]==d){rec[x]++;splay(rt,x,rt);return;}
        int nxt=d<v[x]?0:1;
        if(!ch[x][nxt])
        {
            ch[x][nxt]=++tot;
            v[tot]=d;
            sz[tot]=rec[tot]=1;
            fa[tot]=x;
            ch[tot][0]=ch[tot][1]=0;
            splay(rt,tot,rt);
            return;
        }
        x=ch[x][nxt];
    }
}
inline int splay_rk(int &rt,int d)
{
    int x=rt,ans=0;
    while(1)
    {
        if(!x){return ans;}
        if(v[x]==d){ans+=sz[ch[x][0]];splay(rt,x,rt);return ans;}
        int nxt=d<v[x]?0:1;
        if(nxt==1) ans+=sz[ch[x][0]]+rec[x];
        x=ch[x][nxt];
    }
}
inline int splay_find(int &rt,int d)
{
    int x=rt;
    while(1)
    {
        if(!x) return 0;
        if(v[x]==d){splay(rt,x,rt);return x;}
        int nxt=d<v[x]?0:1;
        x=ch[x][nxt];
    }
}
inline void splay_del(int &rt,int d)
{
    int x=splay_find(rt,d);
    if(!x) return;
    if(rec[x]>=2){rec[x]--,sz[x]--;return;}
    if(!ch[x][0]&&!ch[x][1]){rt=0;return;}
    if(!ch[x][0]){rt=ch[x][1];fa[rt]=0;return;}
    if(!ch[x][1]){rt=ch[x][0];fa[rt]=0;return;}
    int left=ch[x][0];
    while(ch[left][1]) left=ch[left][1];
    splay(rt,left,ch[x][0]);
    fa[ch[x][1]]=left;
    ch[left][1]=ch[x][1];
    fa[left]=0;
    rt=left;
    splay_pushup(left);
}
inline int splay_lower(int &rt,int d)
{
    int x=rt,ans=-inf;
    while(x)
    {
        if(v[x]<d) ans=max(ans,v[x]);
        int nxt=d<=v[x]?0:1;
        x=ch[x][nxt];
    }
    return ans;
}
inline int splay_upper(int &rt,int d)
{
    int x=rt,ans=inf;
    while(x)
    {
        if(v[x]>d) ans=min(ans,v[x]);
        int nxt=d<v[x]?0:1;
        x=ch[x][nxt];
    }
    return ans;
}
//----------------------Seg_Tree--------------------------
void seg_insert(int k,int l,int r,int x,int d)
{
    splay_insert(rt[k],d);
    if(l==r) return;
    int mid=(l+r)>>1;
    if(x<=mid) seg_insert(k<<1,l,mid,x,d);
    else seg_insert(k<<1|1,mid+1,r,x,d);
}
int seg_rk(int k,int l,int r,int ql,int qr,int d)
{

    if(ql<=l&&r<=qr){return splay_rk(rt[k],d);}
    int ans=0,mid=(l+r)>>1;
    if(ql<=mid) ans+=seg_rk(k<<1,l,mid,ql,qr,d);
    if(qr>=mid+1) ans+=seg_rk(k<<1|1,mid+1,r,ql,qr,d);
    return ans;
}
void seg_change(int k,int l,int r,int x,int d)
{
    splay_del(rt[k],a[x]),splay_insert(rt[k],d);
    if(l==r){a[x]=d;return;}
    int mid=(l+r)>>1;
    if(x<=mid) seg_change(k<<1,l,mid,x,d);
    else seg_change(k<<1|1,mid+1,r,x,d);
}
int seg_lower(int k,int l,int r,int ql,int qr,int d)
{
    if(ql<=l&&r<=qr) return splay_lower(rt[k],d);
    int ans=-inf,mid=(l+r)>>1;
    if(ql<=mid) ans=max(ans,seg_lower(k<<1,l,mid,ql,qr,d));
    if(qr>=mid+1) ans=max(ans,seg_lower(k<<1|1,mid+1,r,ql,qr,d));
    return ans;
}
int seg_upper(int k,int l,int r,int ql,int qr,int d)
{
    if(ql<=l&&r<=qr) return splay_upper(rt[k],d);
    int ans=inf,mid=(l+r)>>1;
    if(ql<=mid) ans=min(ans,seg_upper(k<<1,l,mid,ql,qr,d));
    if(qr>=mid+1) ans=min(ans,seg_upper(k<<1|1,mid+1,r,ql,qr,d));
    return ans;
}
inline int seg_kth(int ql,int qr,int k)
{
    int l=0,r=maxn+1,ans;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(seg_rk(1,1,n,ql,qr,mid)+1<=k) ans=mid,l=mid+1;
        else r=mid-1;
    }
    return ans;
}
int main()
{
    n=read(),m=read();
    rep(i,1,n) a[i]=read(),seg_insert(1,1,n,i,a[i]),maxn=max(maxn,a[i]);
    rep(i,1,m)
    {
        int opt=read(),x=read(),y=read(),k;
        if(opt==1) k=read(),printf("%d\n",seg_rk(1,1,n,x,y,k)+1);
        if(opt==2) k=read(),printf("%d\n",seg_kth(x,y,k));
        if(opt==3) maxn=max(maxn,y),seg_change(1,1,n,x,y);
        if(opt==4) k=read(),printf("%d\n",seg_lower(1,1,n,x,y,k));
        if(opt==5) k=read(),printf("%d\n",seg_upper(1,1,n,x,y,k));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/MYsBlogs/p/11403309.html

时间: 2024-10-10 09:50:21

树套树-线段树套平衡树的相关文章

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

题目大意:有一些位置,这些位置上可以放若干个数字.现在有两种操作. 1.在区间l到r上添加一个数字x 2.求出l到r上的第k大的数字是什么 思路:这种题一看就是树套树,关键是怎么套,怎么写.(话说我也不会来着..)最容易想到的方法就是区间线段树套一个权值线段树,但是区间线段树上的标记就会变得异常复杂.所以我们就反过来套,用权值线段树套区间线段树.这样修改操作在外线段树上就变成了单点修改,外线段树就不用维护标记了.在里面的区间线段树上维护标记就容易多了.具体实现见代码. CODE: #includ

[bzoj3932][CQOI2015]任务查询系统-题解[主席树][权值线段树]

Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行 ),其优先级为Pi.同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同.调度系统会经常向 查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个 )的优先级之和是多少.特别的,如

主席树/函数式线段树/可持久化线段树

什么是主席树 可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本.同时充分利用它们之间的共同数据来减少时间和空间消耗. 因此可持久化线段树也叫函数式线段树又叫主席树. 可持久化数据结构 在算法执行的过程中,会发现在更新一个动态集合时,需要维护其过去的版本.这样的集合称为是可持久的. 实现持久集合的一种方法时每当该集合被修改时,就将其整个的复制下来,但是这种方法会降低执行速度并占用过多的空间. 考虑一个持久集合S. 如图所示,对集合的

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

hdu 1166 树状数组 线段树

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 51177    Accepted Submission(s): 21427 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

BZOJ2243 (树链剖分+线段树)

Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. 解题分析 树链剖分+线段树. 开一个记录类型,记录某一段区间的信息.l 表示区间最左侧的颜色 , r 表示区间最右侧的颜色 , sum 表示区间中颜色段数量. 合并时判断一下左区间的右端点和有区间的左端点的颜色是否一样. 树上合并时需要用两个变量ans1,ans2来存储.ans1表示x往上走时形成的链的信息,

bzoj4304 (树链剖分+线段树)

Problem T2 (bzoj4304 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 解题分析 练手题.树链剖分+线段树. 参考程序 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #incl