1. 程式人生 > >主席樹,喵~

主席樹,喵~

str hdu4417 ffi pac 直接 發現 names 很多 Go

稍微總結一下主席樹吧

Too Difficult!搞了一天搞出一大堆怎麽令人悲傷的辣雞代碼。總之先總結一下吧,以後碰到這種問題直接拿去毒害隊友好了。


Lv.1 最基本的操作

  • 區間k大值

  • 區間內有多少個數字小於等於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);
}

兩道入門題:POJ2104,HDU4417

目前對主席樹很naive的理解:主席樹相當於對每一個前綴都維護一個線段樹,然後發現相鄰兩棵線段樹長得好像哎!然後就是資源重復利用了。


既然是維護每一個前綴,所以,我們不僅能拿主席樹來施展線性結構,還能施展樹狀結構!比如說我們可以查詢樹上兩點間路徑點權的k小值。

Lv.2 樹上路徑上點權k小值

栗子:SPOJ-COT

線性結構上

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

樹狀結構上

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


Lv.2 矩形內有多少個點

給出很多個點。Q組詢問,每組詢問查詢一個矩形內有幾個點。

按橫坐標排序,把縱坐標放到主席樹上,然後就相當於區間內有多少個數字小於等於x啦!

CF853C

把細節考慮好!還是很友好的。

#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);
    }
}

以上,於4/28,mark一下。

之後,待補的坑:

  • BIT套主席樹
  • 主席樹的區間更新

學數據結構是不可能學數據結構的,這輩子都不可能學數據結構!

主席樹,喵~