权值线段树
HDU1396 Minimum Inversion Number
求序列最小逆序数
权值线段树单点更新区间查询
#include<bits/stdc++.h>
using namespace std;
const int MAX=5e3+5;
int a[MAX],n;
struct P
{
int l,r,v;
}b[MAX<<2];
void build(int rt,int l,int r)
{
b[rt].l=l;b[rt].r=r;b[rt].v=0;
if(l==r) return ;
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
}
void update(int rt,int pos)
{
if(b[rt].l==b[rt].r) {++b[rt].v;return;}
int mid=(b[rt].l+b[rt].r)>>1;
if(pos<=mid) update(rt<<1,pos);
else update(rt<<1|1,pos);
b[rt].v=b[rt<<1].v+b[rt<<1|1].v;
}
int query(int rt,int L,int R)
{
if(b[rt].l==L&&b[rt].r==R) return b[rt].v;
int mid=(b[rt].l+b[rt].r)>>1;
if(R<=mid) return query(rt<<1,L,R);
else if(L>mid) return query(rt<<1|1,L,R);
else return query(rt<<1,L,mid)+query(rt<<1|1,mid+1,R);
}
int main()
{
while(~scanf("%d",&n))
{
int sum=0;
build(1,1,n+1);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);++a[i];
sum+=query(1,a[i]+1,n+1);
update(1,a[i]);
}
int ans=sum;
for(int i=n;i>0;--i)
{
sum=sum-(n-a[i])+(a[i]-1);
ans=min(ans,sum);
}
printf("%d\n",ans);
}
return 0;
}
指针版动态开点,减少内存
#include<bits/stdc++.h>
using namespace std;
const int MAX=5e3+5;
int a[MAX],n,cnt;
struct P
{
int l,r,v;
P *ls,*rs;
}b[MAX<<1];
void build(P *rt,int l,int r)
{
rt->l=l;rt->r=r;rt->v=0;
if(l==r) return ;
int mid=(l+r)>>1;
rt->ls=&b[++cnt];
rt->rs=&b[++cnt];
build(rt->ls,l,mid);
build(rt->rs,mid+1,r);
}
void update(P *rt,int pos)
{
if(rt->l==rt->r) {++rt->v;return ;}
int mid=(rt->l+rt->r)>>1;
if(pos<=mid) update(rt->ls,pos);
else update(rt->rs,pos);
rt->v=rt->ls->v+rt->rs->v;
}
int query(P *rt,int L,int R)
{
if(rt->l==L&&rt->r==R) return rt->v;
int mid=(rt->l+rt->r)>>1;
if(R<=mid) return query(rt->ls,L,R);
else if(L>mid) return query(rt->rs,L,R);
else return query(rt->ls,L,mid)+query(rt->rs,mid+1,R);
}
int main()
{
while(~scanf("%d",&n))
{
cnt=0;
int sum=0;
build(b,1,n+1);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);++a[i];
sum+=query(b,a[i]+1,n+1);
update(b,a[i]);
}
int ans=sum;
for(int i=n;i>0;--i)
{
sum=sum-(n-a[i])+(a[i]-1);
ans=min(ans,sum);
}
printf("%d\n",ans);
}
return 0;
}
空间mlog(n)动态开点
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include <stack>
#include<vector>
#define half (l+r)>>1;
using namespace std;
int n,m;
const int maxn=400000;
struct hzw
{
int sum;
int add;
int lc;
int rc;
}t[maxn];
int a[maxn],tot;
inline void update(int &s,int l,int r,int cl,int cr,int x)
{
if (!s) s=++tot;
t[s].sum+=(cr-cl+1)*x;
if (l==cl&&r==cr)
{
t[s].add+=x;
return ;
}
int mid=half;
if (cr<=mid) update(t[s].lc,l,mid,cl,cr,x);
else if (cl>mid) update(t[s].rc,mid+1,r,cl,cr,x);
else {
update(t[s].lc,l,mid,cl,mid,x);
update(t[s].rc,mid+1,r,mid+1,cr,x);
}
}
inline int query(int s,int l,int r,int cl,int cr,int cnt)
{
if (!s) return 0;
if (l==cl&&r==cr)
{
return cnt*(cr-cl+1)+t[s].sum;
}
int mid=half;
if (cr<=mid) return query(t[s].lc,l,mid,cl,cr,cnt+t[s].add);
else if (cl>mid) return query(t[s].rc,mid+1,r,cl,cr,cnt+t[s].add);
else {
return query(t[s].lc,l,mid,cl,mid,t[s].add+cnt)+query(t[s].rc,mid+1,r,mid+1,cr,cnt+t[s].add);
}
}
int main() {
int ans=0,cur;
tot++;
cin>>n>>m;
int root=1;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for (int i=1;i<=n;++i) update(root,1,n,i,i,a[i]);
for(int i=1,q,x,y;i<=m;i++)
{
scanf("%d%d%d",&q,&x,&y);
if(q==1)
{ scanf("%d",&cur);
update(root,1,n,x,y,cur);
}
else
{
cout<<query(1,1,n,x,y,0)<<endl;
}
}
return 0;
}
主席树-可持续化权值线段树
求区间第k大的元素
前缀和、动态加点、离散化
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
int root[MAX],a[MAX],n,m,cnt;
struct P
{
int l,r,v;
}b[MAX*25];
vector<int >v;
int id(int x)
{
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void update(int l,int r,int &x,int y,int pos)
{
b[++cnt]=b[y];++b[cnt].v;x=cnt;
if(l==r) return ;
int mid=(l+r)>>1;
if(pos<=mid) update(l,mid,b[x].l,b[y].l,pos);
else update(mid+1,r,b[x].r,b[y].r,pos);
}
int query(int l,int r,int x,int y,int k)
{
if(l==r) return l;
int mid=(l+r)>>1;
int sum=b[b[y].l].v-b[b[x].l].v;
if(sum>=k) return query(l,mid,b[x].l,b[y].l,k);
else return query(mid+1,r,b[x].r,b[y].r,k-sum);
}
int main()
{
int x,y,k;
while(~scanf("%d%d",&n,&m))
{
cnt=0;v.clear();
for(int i=1;i<=n;++i) scanf("%d",&a[i]),v.push_back(a[i]);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;++i) update(1,n,root[i],root[i-1],id(a[i]));
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&x,&y,&k);
printf("%d\n",v[query(1,n,root[x-1],root[y],k)-1]);
}
}
return 0;
}