题目概述
给出一个
n
排列和
解题报告
直接树状数组+主席树就好了!树状数组+主席树就是修改和询问的时候有
log2n
个点,其他都一样。
然而你会RE or MLE,于是开始黑科技……因为这道题不需要历史版本,所以不用可持久化,但不可能和朴素做法一样建
n
棵线段树。不过我们可以一边修改一边新建,只有在某个节点被用到的时候才建出该节点,这样空间就比
2017.10.14upd:其实这就是动态开点?!
示例程序
#include<cstdio>
using namespace std;
typedef long long LL;
const int maxn=100000,maxt=10000000;
int n,m,a[maxn+5],pos[maxn+5];LL ans=0;
struct node {node* son[2];int sum;};
typedef node* P_node;
node tem[maxt];P_node si=tem,ro[maxn+5];
void Insert(P_node &p,int pos,int k,int l=1,int r=n)
{
if (pos<l||r<pos) return;p=p?p:si++;p->sum+=k;if (l==r) return;int mid=l+(r-l>>1);
Insert(p->son[0],pos,k,l,mid);Insert(p->son[1],pos,k,mid+1,r);
}
int Query(P_node p,int L,int R,int l=1,int r=n)
{
if (!p||R<l||r<L) return 0;if (L<=l&&r<=R) return p->sum;int mid=l+(r-l>>1);
return Query(p->son[0],L,R,l,mid)+Query(p->son[1],L,R,mid+1,r);
}
inline void Update(int x,int num,int tem) {for (int i=x;i<=n;i+=i&-i) Insert(ro[i],num,tem);}
inline int Ask(int x,int L,int R) {int sum=0;for (int i=x;i;i-=i&-i) sum+=Query(ro[i],L,R);return sum;}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d%d",&n,&m);for (int i=1;i<=n;i++) ro[i]=0;
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);Update(pos[a[i]]=i,a[i],1);
ans+=Ask(i-1,a[i]+1,n);
}
for (int i=1,x;i<=m;i++)
{
scanf("%d",&x);printf("%lld\n",ans);Update(pos[x],x,-1);
ans-=Ask(pos[x]-1,x+1,n)+Ask(n,1,x-1)-Ask(pos[x],1,x-1);
}
return 0;
}