学习笔记(带修主席树)
带修主席树
- 感谢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;
}