模板
主席树
(带离散)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int N=2e5+10;
struct TREE{
int l,r,size;
}tree[N*20];
int h[N],a[N],root[N];
int cnt;
void insert(int x,int &y,int v,int l,int r)
{
y=++cnt;
tree[y]=tree[x];
tree[y].size++;
if(l==r)
return;
int mid=(l+r)>>1;
if(v>mid)
insert(tree[x].r,tree[y].r,v,mid+1,r);
else
insert(tree[x].l,tree[y].l,v,l,mid);
}
int query(int x,int y,int k,int l,int r)
{
if(l==r)
return l;
int tot,mid;
tot=tree[tree[y].l].size-tree[tree[x].l].size;
mid=(l+r)>>1;
if(tot<k)
return query(tree[x].r,tree[y].r,k-tot,mid+1,r);
else
return query(tree[x].l,tree[y].l,k,l,mid);
}
int main()
{
int n,m,i,L,l,r,k,x;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
h[i]=a[i];
}
sort(h+1,h+n+1);
L=unique(h+1,h+n+1)-h-1;
for(i=1;i<=n;i++)
{
x=lower_bound(h+1,h+L+1,a[i])-h;
insert(root[i-1],root[i],x,1,L);
}
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",h[query(root[l-1],root[r],k,1,L)]);
}
return 0;
}
带修主席树(树状数组套线段树)
注意:
- 空间为即O(Nlog2N)(实测1e5数据90N可过)
模板(CQOI2011动态逆序对)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e5+10;
struct apple{
int size,l,r;
}tree[N*90];
int root[N],a[N],vist[N],p[N],h[N];
long long ans[N];
int cnt,n;
int lowbit(int x){ return x&(-x); }
void insert(int &x,int v,int l,int r) // 线段树插入
{
if(!x) x=++cnt;
tree[x].size++;
if(l==r) return;
int mid=(l+r)>>1;
if(v>mid)
insert(tree[x].r,v,mid+1,r);
else
insert(tree[x].l,v,l,mid);
}
void ins(int x) //树状数组插入
{
for(int i=x;i<=n;i+=lowbit(i))
insert(root[i],a[x],1,n);
}
long long query(int x,int v,int l,int r) //线段树查询
{
if(!x) return 0;
if(r<=v) return tree[x].size;
if(l>v) return 0;
int mid=(l+r)>>1;
return query(tree[x].l,v,l,mid)+query(tree[x].r,v,mid+1,r);
}
long long query(int x,int v) //树状数组查询
{
long long now=0;
for(int i=x;i>0;i-=lowbit(i))
now+=query(root[i],v,1,n);
return now;
}
long long solve(int x)
{
return query(n,a[x])+query(x,n)-2LL*query(x,a[x]);
}
int main()
{
int m,i;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
h[a[i]]=i;
}
for(i=1;i<=m;i++)
{
scanf("%d",&p[i]);
vist[h[p[i]]]=1;
}
long long now=0;
for(i=1;i<=n;i++)
if(!vist[i])
{
now+=solve(i);
ins(i);
}
for(i=m;i>0;i--)
{
now+=solve(h[p[i]]);
ans[i]=now;
ins(h[p[i]]);
}
for(i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}
题目
- CQOI2011动态逆序对
题解:
删除操作,倒过来变成插入操作。
与x有关的逆序对数 = x前面比x大的 + x后面比x小的 = x前面的数 - x前面比x小的 + 所有比小的 - x前面比x小的
所以,仅需实现查找x前面比x小的数即可
代码为上面模板