学习笔记(带修主席树)

大城市里の小女人 提交于 2020-03-12 07:31:52
带修主席树
  • 感谢YMY大佬非常非常详细的口糊和debug(v.) ,首先主席树是离线算法。
  • 普通主席树是权值线段树,求区间里有几个数,就是用前缀和相减的方式。
  • 其实带修主席树也大同小异。
算法实现
  • 首先你需要离线所有的操作,主要是要将修改之后的值也离散进取
  • 对于每次修改,用树状数组的方式每次加lowbit(),对每个点都insert一下。
  • 对于每次询问,先开两个数组,将左右端点树状数组的跳的点都存下来,每次查询区间都用所用又端点减所有左端点,进左右子树时,也要将这些点换成左右子树。

洛谷 Dynamic Ranking

#include<bits/stdc++.h>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=1e4+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
    T ans=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
    return ans*f;
}
template<typename T>void write(T x,char y)
{
    if(x==0)
    {
        putchar('0');putchar(y);
        return;
    }
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    static char wr[20];
    int top=0;
    for(;x;x/=10)wr[++top]=x%10+'0';
    while(top)putchar(wr[top--]);
    putchar(y);
}
void file()
{
    #ifndef ONLINE_JUDGE
        freopen("2617.in","r",stdin);
        freopen("2617.out","w",stdout); 
#endif 
} 
int n,m;
int size,cnt,rt[N*200],ls[N*200],rs[N*200],sz[N*200];
int a[N],b[N<<1];
int opt[N][5];
void input()
{
    n=read<int>();m=read<int>();
    For(i,1,n)a[i]=b[i]=read<int>();
    size=n;
    char s[10];
    For(i,1,m)
    {
        scanf("%s",s);
        opt[i][1]=read<int>();opt[i][2]=read<int>();
        if(s[0]=='Q')opt[i][0]=1,opt[i][3]=read<int>(); 
        else if(s[0]=='C')opt[i][0]=2,b[++size]=opt[i][2];
    }
}
#define mid ((l+r)>>1)
void insert(int &h,int pre,int l,int r,int pos,int v)
{
    h=++cnt;ls[h]=ls[pre];rs[h]=rs[pre];sz[h]=sz[pre]+v;
    if(l==r)return;
    if(pos<=mid)insert(ls[h],ls[pre],l,mid,pos,v);
    else insert(rs[h],rs[pre],mid+1,r,pos,v);
}
void add(int pos,int v)
{
    int k=lower_bound(b+1,b+size+1,a[pos])-b;
    for(;pos<=n;pos+=pos&-pos)insert(rt[pos],rt[pos],1,size,k,v);
}
void init()
{
    sort(b+1,b+size+1);
    size=unique(b+1,b+size+1)-(b+1);
    For(i,1,n)add(i,1);
}
int lef[N],rig[N],tr,tl;
int query(int l,int r,int k)
{
    if(l==r)return mid;
    static int sum;
    sum=0;
    For(i,1,tl)sum-=sz[ls[lef[i]]];
    For(i,1,tr)sum+=sz[ls[rig[i]]];
    if(sum>=k)
    {
        For(i,1,tl)lef[i]=ls[lef[i]];
        For(i,1,tr)rig[i]=ls[rig[i]];
        return query(l,mid,k);
    }
    else 
    {
        For(i,1,tl)lef[i]=rs[lef[i]];
        For(i,1,tr)rig[i]=rs[rig[i]];
        return query(mid+1,r,k-sum);
    }
}
void work()
{
    For(i,1,m)
    {
        if(opt[i][0]==1)
        {
            tl=tr=0;
            for(register int j=opt[i][1]-1;j;j-=j&-j)lef[++tl]=rt[j];
            for(register int j=opt[i][2];j;j-=j&-j)rig[++tr]=rt[j];
            write(b[query(1,size,opt[i][3])],'\n');
        }
        else if(opt[i][0]==2)
        {
            add(opt[i][1],-1);
            a[opt[i][1]]=opt[i][2];
            add(opt[i][1],1);
        }
    }
}
int main()
{
    file();
    input();
    init();
    work();
    return 0;
}

洛谷 Count on a tree

#include<bits/stdc++.h>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=1e5+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
    T ans=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
    return ans*f;
}
template<typename T>void write(T x,char y)
{
    if(x==0)
    {
        putchar('0');putchar(y);
        return;
    }
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    static char wr[20];
    int top=0;
    for(;x;x/=10)wr[++top]=x%10+'0';
    while(top)putchar(wr[top--]);
    putchar(y);
}
void file()
{
    #ifndef ONLINE_JUDGE
        freopen("2633.in","r",stdin);
        freopen("2633.out","w",stdout);
    #endif
}
int n,m;
int a[N],b[N];
struct edge
{
    int v,nex;
}e[N<<1];
int head[N],tt;
void add(int x,int y){++tt;e[tt].v=y;e[tt].nex=head[x];head[x]=tt;}
void input()
{
    int x,y;
    n=read<int>();m=read<int>();
    For(i,1,n)a[i]=b[i]=read<int>();
    For(i,1,n-1)
    {
        x=read<int>();y=read<int>();
        add(x,y);add(y,x);
    }
}
int top[N],dep[N],son[N],fa[N],size[N],id[N],order[N],dfs_clock;
int rt[N<<6],ls[N<<6],rs[N<<6],sum[N<<6],sz,cnt;
void dfs1(int u,int pre)
{
    dep[u]=dep[pre]+1;fa[u]=pre;size[u]=1;
    int v;
    for(register int i=head[u];i;i=e[i].nex)
    {
        v=e[i].v;
        if(v^pre)
        {
            dfs1(v,u);
            size[u]+=size[v];
            if(size[son[u]]<size[v])son[u]=v;
        }
    }
}
void dfs2(int u,int start)
{
    top[u]=start;id[u]=++dfs_clock;order[dfs_clock]=u;
    if(!son[u])return;
    dfs2(son[u],start);
    int v;
    for(register int i=head[u];i;i=e[i].nex)
    {
        v=e[i].v;
        if(v^fa[u]&&v^son[u])dfs2(v,v);
    }
}
#define mid ((l+r)>>1)
void build(int &h,int l,int r)
{
    h=++cnt;
    if(l==r)return;
    build(ls[h],l,mid);build(rs[h],mid+1,r);
}
void insert(int &h,int pre,int l,int r,int pos)
{
    h=++cnt;ls[h]=ls[pre];rs[h]=rs[pre];sum[h]=sum[pre]+1;
    if(l==r)return;
    if(pos<=mid)insert(ls[h],ls[pre],l,mid,pos);
    else insert(rs[h],rs[pre],mid+1,r,pos);
}
void init()
{
    sort(b+1,b+n+1);
    sz=unique(b+1,b+n+1)-(b+1);
    build(rt[0],1,sz);
    For(i,1,n)insert(rt[i],rt[i-1],1,sz,lower_bound(b+1,b+sz+1,a[order[i]])-b);
}
int lans;
int tl,tr,lef[N],rig[N];
void query_tree(int x,int y)
{
    tl=tr=0;
    int tx=top[x],ty=top[y];
    while(tx^ty)
    {
        if(dep[tx]<dep[ty])swap(tx,ty),swap(x,y);
        lef[++tl]=rt[id[tx]-1];rig[++tr]=rt[id[x]];
        x=fa[tx];tx=top[x];
    }
    if(dep[x]>dep[y])swap(x,y);
    lef[++tl]=rt[id[x]-1];rig[++tr]=rt[id[y]];
}
int query(int l,int r,int k)
{
    if(l==r)return l;
    static int num;num=0;
    For(i,1,tl)num-=sum[ls[lef[i]]];
    For(i,1,tr)num+=sum[ls[rig[i]]];
    if(num>=k)
    {
        For(i,1,tl)lef[i]=ls[lef[i]];
        For(i,1,tr)rig[i]=ls[rig[i]];
        return query(l,mid,k);
    }
    else
    {
        For(i,1,tl)lef[i]=rs[lef[i]];
        For(i,1,tr)rig[i]=rs[rig[i]];
        return query(mid+1,r,k-num);
    }
}
void work()
{
    int u,v,k;
    For(i,1,m)
    {
        u=read<int>()^lans;v=read<int>();k=read<int>();
        query_tree(u,v);
        lans=b[query(1,sz,k)];
        printf("%d\n",lans);
    }
}
int main()
{
    file();
    input();
    dfs1(1,0);
    dfs2(1,1);
    init();
    work();
    return 0;
}

洛谷3175动态逆序对

// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=2e5+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
    T ans=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
    return ans*f;
}
template<typename T>void write(T x,char y)
{
    if(x==0)
    {
        putchar('0');putchar(y);
        return;
    }
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    static char wr[20];
    int top=0;
    for(;x;x/=10)wr[++top]=x%10+'0';
    while(top)putchar(wr[top--]);
    putchar(y);
}
void file()
{
    #ifndef ONLINE_JUDGE
        freopen("3157.in","r",stdin);
        freopen("3157.out","w",stdout);
    #endif
}
int n,m;
int a[N],p[N];
void input()
{
    n=read<int>();m=read<int>();
    For(i,1,n)
    {
        a[i]=read<int>();
        p[a[i]]=i;
    }
}
int rt[N],ls[N<<6],rs[N<<6],sum[N<<6],cnt;
int tl,tr,lef[N],rig[N];
#define mid ((l+r)>>1)
#define sz n
void insert(int &h,int pre,int l,int r,int pos,int v)
{
    h=++cnt;ls[h]=ls[pre];rs[h]=rs[pre];sum[h]=sum[pre]+v;
    if(l==r)return;
    if(pos<=mid)insert(ls[h],ls[pre],l,mid,pos,v);
    else insert(rs[h],rs[pre],mid+1,r,pos,v);
}
void add(int pos,int v)
{
    int k=a[pos];
    for(;pos<=n;pos+=pos&-pos)insert(rt[pos],rt[pos],1,sz,k,v);
}
ll ans;
int c[N];
int num1[N],num2[N];
int get_sum(int x)
{
    int res=0;
    for(;x;x-=x&-x)res+=c[x];
    return res;
}
void add_sum(int x,int v)
{
    for(;x<=n;x+=x&-x)c[x]+=v;
}
void cal()
{
    For(i,1,n)
    {
        num1[i]=get_sum(n)-get_sum(a[i]);
        ans+=num1[i];
        add_sum(a[i],1);
    }
    memset(c,0,sizeof c);
    Fordown(i,n,1)
    {
        num2[i]=get_sum(a[i]-1);
        add_sum(a[i],1);
    }
}
void get(int x,int y)
{
    tl=tr=0;
    for(int i=x;i;i-=i&-i)lef[++tl]=rt[i];
    for(int i=y;i;i-=i&-i)rig[++tr]=rt[i];
}
void turl()
{
    For(i,1,tl)lef[i]=ls[lef[i]];
    For(i,1,tr)rig[i]=ls[rig[i]];
}
void turr()
{
    For(i,1,tl)lef[i]=rs[lef[i]];
    For(i,1,tr)rig[i]=rs[rig[i]];
}
int querypre(int x,int y,int v)
{
    if(x>y)return 0;
    get(x-1,y);
    int l=1,r=sz,res=0;
    while(l^r)
    {
        if(v<=mid)
        {
            For(i,1,tl)res-=sum[rs[lef[i]]];
            For(i,1,tr)res+=sum[rs[rig[i]]];
            turl();
            r=mid;
        }
        else
        {
            turr();
            l=mid+1;
        }
    }
    return res;
}
int querynex(int x,int y,int v)
{
    if(x>y)return 0;
    get(x-1,y);
    int l=1,r=sz,res=0;
    while(l^r)
    {
        if(v>mid)
        {
            For(i,1,tl)res-=sum[ls[lef[i]]];
            For(i,1,tr)res+=sum[ls[rig[i]]];
            turr();
            l=mid+1;
        }
        else
        {
            turl();
            r=mid;
        }
    }
    return res;
}
void work()
{
    int x;
    For(i,1,m)
    {
        x=read<int>();
        write(ans,'\n');
        x=p[x];
        ans=ans-(num1[x]+num2[x]-querypre(1,x-1,a[x])-querynex(x+1,n,a[x]));
        add(x,1);
    }
}
int main()
{
    file();
    input();
    cal();
    work();
    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!