bzoj3524: [Poi2014]Couriers(主席树)

  主席树(可持久化权值线段树)初探...

  修改一个点只对树上logn个点有影响,所以新建logn个点就行了,总共新建mlogn个点。

  查询一个区间[l,r],相当于将数一个一个加进树,询问第l到第r次操作,这个可以用前缀解决。

  板子不慢。。在第三页,KPM写指针的主席树貌似跑的飞快

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long 
using namespace std;
const int maxn=500010,inf=1e9;
struct poi{int size,lt,rt;}a[maxn*20];
int n,m,x,y,z,sz,ans;
int root[maxn];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
    k*=f;
}
void build(int &x,int l,int r,int cx)
{
    a[++sz]=a[x];a[sz].size++;x=sz;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(cx<=mid)build(a[x].lt,l,mid,cx);
    else build(a[x].rt,mid+1,r,cx);
}
int query(int x,int y,int l,int r,int cx)
{
    if(l==r)return l;
    int mid=(l+r)>>1;
    if(a[a[y].lt].size-a[a[x].lt].size>=cx)return query(a[x].lt,a[y].lt,l,mid,cx);
    else if(a[a[y].rt].size-a[a[x].rt].size>=cx)return query(a[x].rt,a[y].rt,mid+1,r,cx);
    else return 0;
}
int main()
{
    read(n);read(m);
    for(int i=1;i<=n;i++)
    {
        read(x);
        root[i]=root[i-1];
        build(root[i],1,n,x);
    }
    for(int i=1;i<=m;i++)
    {
        read(x);read(y);
        printf("%d
",query(root[x-1],root[y],1,n,((y-x+1)>>1)+1));
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Sakits/p/7397387.html