Chairman tree, meow~

A little summary of the chairman tree

Too Difficult! It took a day to come up with a lot of sadly spicy chicken code. In short, let’s summarize it first, and if you encounter this kind of problem in the future, you can directly use it to poison your teammates.


Lv.1 the most basic operation

  • Large value of interval k

  • How many numbers in the interval are less than or equal to x

query 操作了解一下
int query(int new_k,int old_k,int l,int r,int x) { // cnt <= x
    if(x<l) return 0; // 这个地方比较喜。小心点。
    if(l==r) return sum[new_k]-sum[old_k];
    int mid=(l+r)>>1;
    if(mid<x) return sum[lson[new_k]]-sum[lson[old_k]]+query(rson[new_k],rson[old_k],mid+1,r,x);
    else return query(lson[new_k],lson[old_k],l,mid,x);
}

Two introductory questions: POJ2104 , HDU4417

At present, I have a very naive understanding of the chairman tree: the chairman tree is equivalent to maintaining a segment tree for each prefix, and then I find that the two adjacent segment trees look like they! So we can open it dynamically!


Since each prefix is ​​maintained, we can not only use the chairman tree to display a linear structure, but also a tree structure! For example, we can query the k small value of the path point weight between two points on the tree.

Lv.2 Small value of point weight k on the path on the tree

Chestnuts: SPOJ-COT

in a linear structure

iterval(l,r)=T(r)-T(l-1)

tree structure

path(u,v) = T(u)+T(v)-T(lca)-T(Parent of lca)


Lv.2 How many points are in the rectangle

Give many points. Q groups of queries, each group queries how many points are within a rectangle.

Sort by the horizontal coordinate, put the vertical coordinate on the chairman tree, and then it is equivalent to how many numbers in the interval are less than or equal to x!

CF853C

Consider the details! Still very friendly.

#include <iostream>
#include <algorithm>
using namespace std;
const int N=6000000+10;
#define f(x) (1LL*x*(x-1)/2)
typedef long long LL;
int lson[N],rson[N],sum[N],root[N],pid;
int n,q,p[N];
void build(int &k,int l,int r){
    k=++pid;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(lson[k],l,mid);
    build(rson[k],mid+1,r);
}
void change(int old,int &k,int l,int r,int pos,int x) {
    k=++pid;
    lson[k]=lson[old],rson[k]=rson[old],sum[k]=sum[old]+x;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(pos<=mid) change(lson[k],lson[k],l,mid,pos,x);
    else change(rson[k],rson[k],mid+1,r,pos,x);
}
int query(int new_k,int old_k,int l,int r,int x) { // cnt <= x
    if(x<l) return 0;
    if(l==r) return sum[new_k]-sum[old_k];
    int mid=(l+r)>>1;
    if(mid<x) return sum[lson[new_k]]-sum[lson[old_k]]+query(rson[new_k],rson[old_k],mid+1,r,x);
    else return query(lson[new_k],lson[old_k],l,mid,x);
}
int count(int x1,int x2,int y1,int y2) { // 
    if(x1>x2||y1>y2) return 0;
    int cnt1 = query(root[x2],root[x1-1],1,n,y1-1);
    int cnt2 = query(root[x2],root[x1-1],1,n,y2);
    return cnt2-cnt1;
} 
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) {
        scanf("%d",&p[i]);
    }
    build(root[0],1,n);
    for(int i=1;i<=n;i++) {
        change(root[i-1],root[i],1,n,p[i],1);
    }
    for(int i=1;i<=q;i++){
        int l,d,r,u;
        scanf("%d%d%d%d",&l,&d,&r,&u);
        int LU = count(1,l-1,u+1,n);
        int LD = count(1,l-1,1,d-1);
        int RU = count(r+1,n,u+1,n);
        int RD = count(r+1,n,1,d-1);

        int L = l-1; int U = n-u; 
        int R = n-r; int D = d-1;
        
        LL A = f(L)+f(R)+f(U)+f(D);
        LL B = f(LU)+f(LD)+f(RU)+f(RD);
        LL ret = 1LL*n*(n-1)/2-(A-B);
        printf("%lld\n", ret);
    }
}

Above, on 4/28, mark it.

After that, the pits to be filled:

  • BIT set chairman tree
  • Interval update of chairman tree

Learning data structures is impossible to learn data structures, and it is impossible to learn data structures in this life!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325022263&siteId=291194637