【HOJ2430】Counting the Algorithms-区间维护
题目大意:有一个长度为2*N的数列,其中1~N的每个整数都出现2次,要将它们两两删除,删除一个元素以后,另一个元素也被消除,并获得等于它们位置标号之差的绝对值的分数,问删除完所有元素之后所能获得的最大分数是多少。
做法:可以发现,当一对元素被另一对元素包含时,先删除外面的一对元素是最优的;如果两对元素所表示的区间有一部分相交,那么先删哪一对结果都是一样的。所以,我们只需维护每对元素之间所剩的元素个数,从前往后删除即可。
以下是本人代码(树状数组):
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,pos[100010]={0},a[200010]={0},c[200010]={0}; //pos[i]:值为i的一对元素的后面那个元素的位置
int ans;
int lowbit(int i)
{
return i&(-i);
}
void add(int x,int a)
{
for(int i=x;i<=2*n;i+=lowbit(i))
c[i]+=a;
}
int sum(int x)
{
int s=0;
for(int i=x;i>0;i-=lowbit(i))
s+=c[i];
return s;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(c,0,sizeof(c));
memset(pos,0,sizeof(pos));
ans=0;
for(int i=1;i<=2*n;i++)
{
scanf("%d",&a[i]);
pos[a[i]]=i;
add(i,1);
}
for(int i=1;i<=2*n;i++)
{
if (a[i])
{
ans+=sum(pos[a[i]])-sum(i);
add(i,-1);
add(pos[a[i]],-1);
a[pos[a[i]]]=0;a[i]=0;
}
}
printf("%d\n",ans);
}
return 0;
}