主席树
暂时小结
1.查询区间有多少个不同的数//可以用树状数组,线段树,莫队算法
3.动态求区间的第k大//全部修改后查询 //修改同时查询
4.查询某区间比指定的数大的个数//小的个数
5.数上路径点权第k大

静态区间第k大

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn =200010;
int n, m;
int cnt;
struct node//存树
{
   
    int L, R;//分别指向左右子树
    int sum;//该节点所管辖区间范围内数的个数
}Tree[maxn * 20];
struct value//值 //离散化
{
   
    int x;//值的大小
    int id;//离散之前在原数组中的位置
} Value[maxn];
bool cmp(value v1, value v2)//排序从到小
{
   
    return v1.x < v2.x;
}
int root[maxn];//多颗线段树的根节点
int yy[maxn];//原数组离散之后的数组
void update(int num, int &rt, int l, int r)
{
   
    Tree[cnt++] = Tree[rt];
    rt = cnt - 1;
    Tree[rt].sum++;
    if(l == r) return;
    int mid = (l + r)>>1;
    if(num <= mid)
        update(num,Tree[rt].L,l,mid);
    else
        update(num,Tree[rt].R,mid+1,r);
}
int query(int i,int j,int k,int l,int r)
{
   
    int d=Tree[Tree[j].L].sum-Tree[Tree[i].L].sum;
    if(l==r) return l;
    int mid=(l+r)>>1;
    if(k<=d)
        return query(Tree[i].L,Tree[j].L,k,l,mid);
    else return query(Tree[i].R, Tree[j].R,k-d,mid+1,r);
}
int main()
{
   
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
    {
   
        scanf("%d",&Value[i].x);
        Value[i].id=i;
    }
    //进行离散化
    sort(Value + 1,Value+n+1, cmp);
    for(int i=1; i<=n; i++)
    {
   
        yy[Value[i].id]=i;
    }
// init();//初始化
    cnt=1;
    for(int i=1; i<=n; i++)
    {
   
        root[i]=root[i - 1];
        update(yy[i],root[i],1,n);
    }
    int left, right,k;
    for(int i = 1; i <= m; i++)
    {
   
        scanf("%d%d%d", &left, &right, &k);
        printf("%d\n", Value[query(root[left - 1], root[right], k, 1, n)].x);
    }
    return 0;
}

数组形式 静态区间第k大

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int MM=200010;
int node,n,m;
int sum[MM*5],rt[MM],lc[MM*5],rc[MM*5];
int a[MM],b[MM];
int p;
void build(int &t,int l,int r)//建树
{
   
    t=++node;
    if(l==r)
        return;
    int mid=((l+r)>>1);
    build(lc[t],l,mid);
    build(rc[t],mid+1,r);
}
int update(int o,int l,int r)//更新
{
   
    int rt=++node;
    lc[rt]=lc[o];
    rc[rt]=rc[o];
    sum[rt]=sum[o]+1;
    if(l==r)
        return rt;
    int mid=((l+r)>>1);
    if(p<=mid)
        lc[rt]=update(lc[rt],l,mid);
    else
        rc[rt]=update(rc[rt],mid+1,r);
    return rt;
}
int query(int u,int v,int l,int r,int k)//查询
{
   
    int ans,mid=((l+r)>>1),x=sum[lc[v]]-sum[lc[u]];//前缀和
    if(l==r)
        return l;
    if(x>=k)//说明在左子树
        ans=query(lc[u],lc[v],l,mid,k);//
    else
        ans=query(rc[u],rc[v],mid+1,r,k-x);
    return ans;
}
int main()
{
   
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
    {
   
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+n+1);//离散化
    int q=unique(b+1,b+n+1)-b-1;//
    build(rt[0],1,q);
    for(register int i=1; i<=n; i++)
    {
   
        p=lower_bound(b+1,b+q+1,a[i])-b;//二分
        rt[i]=rt[i-1];
        rt[i]=update(rt[i],1,q);
    }
    int l,r,k,ans;
    while(m--)
    {
   
        scanf("%d%d%d",&l,&r,&k);
        ans=query(rt[l-1],rt[r],1,q,k);
        printf("%d\n",b[ans]);
    }
    return 0;
}
//动态求第k大的值(ZO2112)
Q查询
C改变第i个的值为val
树状数组套主席树
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn = 6e4+5;
const int maxm = 1e4+5;
int T[maxn],S[maxn],L[maxn*32],R[maxn*32],sum[maxn*32];
/*n是原序列个数 T[i]表示第i棵线段树的根节点编号 S[i]表示树状数组思维建的第i棵线段树的根节点编号 L[i]表示节点i的左子节点编号 R[i]表示节点i的右子节点编号 sum[i]表示节点i对应区间中数的个数。*/
char str[60];
int sz[maxn],h[maxn];
int ul[maxn],ur[maxn];
int tot,num,n,q;
struct node
{
   
    int l,r,k;
    bool flag; //ture代表Q,false代表C
} Q[maxm*4]; //存储询问
void build(int& rt,int l,int r)//建树
{
   
    rt = ++tot;
    if(l==r)
        return;
    int mid = (l+r)>>1;
    build(L[rt],l,mid);
    build(R[rt],mid+1,r);
}
void update(int& rt,int pre,int l,int r,int x,int val)//更新
{
   
    rt = ++tot;
    L[rt] = L[pre];
    R[rt] = R[pre];
    sum[rt] = sum[pre]+val;//加val
    if(l==r)
        return;
    int mid =(l+r)>>1;
    if(x<=mid)
        update(L[rt],L[pre],l,mid,x,val);
    else
        update(R[rt],R[pre],mid+1,r,x,val);
}

int lowbit(int x)//树状数组
{
   
    return x&(-x);
}
void add(int x,int val)
{
   
    int res = lower_bound(h+1,h+1+num,sz[x])-h;//
    while(x<=n)
    {
   
        update(S[x],S[x],1,num,res,val);
        x += lowbit(x);
    }
}
int Sum(int x,bool flag)
{
   
    int res=0;
    while(x>0)
    {
   
        if(flag) res += sum[L[ur[x]]];//
        else res += sum[L[ul[x]]];
        x -= lowbit(x);
    }
    return res;
}
int query(int s,int e,int ts,int te,int l,int r,int k)
{
   
    if(l==r) return l;
    int mid = (l+r)>>1;
    int res = Sum(e,true)-Sum(s,false)+sum[L[te]]-sum[L[ts]];//前缀和
    if(k<=res)
    {
   
        for(int i=e; i; i-=lowbit(i))
            ur[i] = L[ur[i]];
        for(int i=s; i; i-=lowbit(i))
            ul[i] = L[ul[i]];
        return query(s,e,L[ts],L[te],l,mid,k);
    }
    else
    {
   
        for(int i=e; i; i-=lowbit(i))
            ur[i] = R[ur[i]];
        for(int i=s; i; i-=lowbit(i))
            ul[i] = R[ul[i]];
        return query(s,e,R[ts],R[te],mid+1,r,k-res);
    }
}
//树状数组 前缀和
int main()
{
   
    int yy;
    scanf("%d",&yy);
    while(yy--)
    {
   
        scanf("%d%d",&n,&q);
        num=0;
        for(int i=1; i<=n; i++)
            scanf("%d",sz+i),h[++num]=sz[i];
        for(int i=1; i<=q; i++)
        {
   
            scanf("%s",str);
            if(str[0]=='Q')//查询
            {
   
                scanf("%d%d%d",&Q[i].l,&Q[i].r,&Q[i].k);
                Q[i].flag=true;
            }
            else
            {
   
                scanf("%d%d",&Q[i].l,&Q[i].r);
                Q[i].flag=false;
                h[++num]=Q[i].r;
            }
        }
        sort(h+1,h+1+num);
        int tmp = unique(h+1,h+1+num)-h-1;//离散化
        num = tmp;
        tot=0;
        build(T[0],1,num);
        for(int i=1; i<=n; i++)
        {
   
            update(T[i],T[i-1],1,num,lower_bound(h+1,h+1+num,sz[i])-h,1);
        }
        for(int i=1; i<=n; i++)
            S[i] = T[0];
        for(int i=1; i<=q; i++)
        {
   
            if(Q[i].flag)//查找
            {
   
                for(int j=Q[i].r; j; j-=lowbit(j))
                    ur[j] = S[j];
                for(int j=Q[i].l-1; j; j-=lowbit(j))
                    ul[j] = S[j];
                printf("%d\n",h[query(Q[i].l-1,Q[i].r,T[Q[i].l-1],T[Q[i].r],1,num,Q[i].k)]);
            }
            else//改变
            {
   
                add(Q[i].l,-1);
                sz[Q[i].l] = Q[i].r;
                add(Q[i].l,1);
            }
        }
    }
    return 0;
}