bzoj1901 动态主席树

动态主席树,相当于树套树,,注意到我们修改的时候影响的是后面,,相当于前缀和的形式,,外层树状数组,,内部要用主席树,,自己打的,,但看的别人模板,,这样不好,,但人家的代码却是比较巧妙,,避免了很多问题,,学习吧,,注意这里修改都要动态开节点并且共用,,,这样树状数组修改才不会修改到同一个节点是不是啊,,,被这个想法卡了好久,,终于还是小恐龙喷了一下火我才明白的,,,

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
#define N 10000
#define M 5000000
using namespace std;
struct data{ char ch; int x,y,z;};
struct node{ int id,val;};
struct tree{ int son[2],sum;};
data que[N+5];
node s[(N<<1)+5];
tree A[M+5];
int n,m,posi,a[N+5],pos[(N<<1)+5],cnt,root[(N<<1)+5],p,q,P[(N<<1)+5],Q[(N<<1)+5],num[(N<<1)+5];
inline bool cmp(node a,node b){ return a.val<b.val;}
inline int lowbit(int x){ return (x&(-x));}
inline int getnum(){
    char c; int num;
    while (!isdigit(c = getchar()));
    num = c -'0';
    while (isdigit(c = getchar())) num = 10 * num + c - '0';
    return num;
}

void init(){
    n = getnum(); m = getnum(); posi = 0; cnt = n;
    for (int i = 1;i <= n; ++i) a[i] = getnum(),s[i].val = a[i],s[i].id = i;
    for (int i = 1;i <= m; ++i){
        cin>>que[i].ch;
        que[i].x = getnum(); 
        que[i].y = getnum();
        if (que[i].ch == 'Q') que[i].z = getnum();
        else s[++cnt].val = que[i].y,s[cnt].id = i + n;
    }
    sort(s + 1,s + cnt + 1,cmp);
    s[0].val = -1;
    for (int i = 1;i <= cnt; ++i){
      if (s[i].val != s[i-1].val) posi++;
      pos[s[i].id] = posi;
      num[posi] = s[i].val;
       }
}

inline void build(int l,int r,int &rt){
    int mid = (l + r)>>1;
    rt = ++cnt; A[rt].sum = 0;
    if (l == r) return;
    build(l,mid,A[rt].son[0]);
    build(mid+1,r,A[rt].son[1]);
}

inline void update(int rt){ A[rt].sum = A[A[rt].son[0]].sum + A[A[rt].son[1]].sum;}

inline void change(int last,int l,int r,int &rt,int x,int c){
    int mid = (l + r)>>1;
    rt = ++cnt;
    A[rt].son[0] = A[last].son[0]; A[rt].son[1] = A[last].son[1]; A[rt].sum = A[last].sum + c;
    if (l == r) return;
    if (x <= mid) change(A[last].son[0],l,mid,A[rt].son[0],x,c);
    if (x > mid ) change(A[last].son[1],mid + 1,r,A[rt].son[1],x,c);
    update(rt);
}

inline void add(int s,int x,int c){ 
   for (int i = s; i <= posi; i += lowbit(i)) change(root[i],1,posi,root[i],x,c);}

inline int query(int l,int r,int k){
    int mid = (l + r)>>1;
    if (l == r) return l;
    int suma = 0,sumb = 0;
    for (int i = 1;i <= p; ++i) suma += A[A[P[i]].son[0]].sum;
    for (int i = 1;i <= q; ++i) sumb += A[A[Q[i]].son[0]].sum;
    int del = sumb - suma;
    bool t;
    if (k <= del) t = 0; else t = 1;
        for (int i = 1;i <= p; ++i) P[i] = A[P[i]].son[t];
        for (int i = 1;i <= q; ++i) Q[i] = A[Q[i]].son[t];
    if (!t) return query(l,mid,k);
    else return query(mid+1,r,k - del);
}

inline int ask(int a,int b,int c){
    p = 0,q = 0;
    for (;a;a -= lowbit(a)) P[++p] = root[a];
    for (;b;b -= lowbit(b)) Q[++q] = root[b];
    return query(1,posi,c);
}

void DO_IT(){
    cnt = 0;
    build(1,posi,root[0]);
    for (int i = 1;i <= n; ++i) add(i,pos[i],1);
    for (int i = 1;i <= m; ++i)
    {
        if (que[i].ch == 'Q') printf("%d\n",num[ask(que[i].x-1,que[i].y,que[i].z)]);
        else {
            add(que[i].x,pos[que[i].x],-1);
            pos[que[i].x] = pos[i+n];
            add(que[i].x,pos[que[i].x],1);
        }
    }
}

int main(){
    init();
    DO_IT();
    return 0;
}

你可能感兴趣的:(bzoj1901 动态主席树)