http://acm.hdu.edu.cn/showproblem.php?pid=4217
题意:给你一个N,K;然后又有K个数i;表示从1,2,3...N个数经过K次操作,每次操作是去掉第i小的数。求所有去掉数的之和。
线段树,删节点并记录所删除的节点。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 262144
#define M 1000000
int n;
struct point
{
int num;
}p[4*N];
int getparent(int m)
{
return m/2;
}
int getlchild(int m)
{
return m*2;
}
int getrchild(int m)
{
return m*2+1;
}
void update(int m)//线段树适宜采用这种更新节点的方式
{
int lc=getlchild(m),rc=getrchild(m);
p[m].num=p[lc].num+p[rc].num;
int m1=getparent(m);
if (m1>0) update(m1);
}
int search(int m,int k)
{
if (m>=N)
{
p[m].num=0;
update(getparent(m));
return m-N+1;
}
int lc=getlchild(m),rc=getrchild(m);
if (p[lc].num>=k) return search(lc,k);
else return search(rc,k-p[lc].num);
}
void init()
{
int i;
for (i=1;i<=n;i++)
{
p[i+N-1].num=1;
int p1=getparent(i+N-1);
update(p1);
}
}
int main()
{
//freopen("a","r",stdin);
int kk,t,i,no,k;
long long count;
scanf("%d",&t);
for (kk=1;kk<=t;kk++)
{
scanf("%d%d",&n,&k);
printf("Case %d: ",kk);
init();
count=0;
for (i=1;i<=k;i++)
{
scanf("%d",&no);
//no=1;
count+=search(1,no);
}
cout<<count<<endl;
}
return 0;
}