您的位置:首页 > 其它

线段树——单点更新(二)

2012-07-22 10:35 134 查看
HDU 4217 Data Structure?

http://acm.hdu.edu.cn/showproblem.php?pid=4217

CZ做的一道题目,我帮忙看了看。

题意:给定N个数(1---N),K个操作,然后给K数,i1,i2,i3.......ik 每次取走当前状态下等的第i个数(从小到大的),问取走的数的和。

给的那个的n为262144可以断定肯定是O(n*log(n))级的算法,所以选定线段树。

叶子节点赋值为1,这些节点存储的就是数的个数,在添加一个val数组记录是哪个数。每次更新将节点a[rt]变成0,找出对应的val[rt]即可。

这里坑爹的地方时sum求和时,要用—int64.wa了很多次才发现。

View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll __int64
#define inf 0x7f7f7f7f
#define MOD 1000000007ll
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100010
#define N 1000005
#define M 200007
using namespace std;

int val[maxn<<2];
int pos[maxn];

void pushup(int rt)
{
val[rt] = val[rt<<1] + val[rt<<1|1];
}
void build(int l,int r,int rt)
{
if (l == r)
{
val[rt] = 1;
return ;
}
int m = (l + r)>>1;
build(lc);
build(rc);
pushup(rt);
}
void update(int pos,int l,int r,int rt)
{
if (l == r)
{
val[rt] = 0;
return ;
}
int m = (l + r)>>1;
if (pos <= m) update(pos,lc);
else update(pos,rc);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if (l >= L && r <= R) return val[rt];
int res = 0;
int m = (l + r)>>1;
if (L <= m) res += query(L,R,lc);
if (R > m) res += query(L,R,rc);
return res;
}
int getpos(int s,int l,int r,int rt)
{
if (l == r) return l;

int m = (l + r)>>1;
if (s <= val[rt<<1]) return  getpos(s,lc);
else
{
s -= val[rt<<1];
return  getpos(s,rc);
}
}
int main()
{
//freopen("din.txt","r",stdin);
int n,i,a;
while (~scanf("%d",&n))
{
if (!n) break;
for (i = 1; i <= n; ++i)
{
scanf("%d",&a);
pos[a] = i;//标记第a个被扔出去的编号
}
build(1,n,1);
int curpos = 1;//当前在手中的点的标号
ll ans = 0;
for (i = 1; i <= n; ++i)
{
int tmp = 0;
if (curpos == pos[i]) ans += 1;//只剩一个点了
else if (curpos < pos[i])//1 2 3 4 5; 3要被删除
{
tmp = query(curpos + 1,pos[i],1,n,1);
ans += (min(tmp,n - i + 1 - tmp) + 1);//n - i + 1 - tmp就是顺时针的个数了,这里比赛时写麻烦了
}
else//同理
{
tmp = query(pos[i],curpos - 1,1,n,1);
ans += (min(tmp,n - i + 1 - tmp) + 1);
}
//printf(">>%d %d %d %d\n",tmp,n - i + 1 - tmp,Min(tmp,n - i + 1 - tmp),(Min(tmp,n - i + 1 - tmp) + 1));//这里发现了用宏定义的Min不行出错
update(pos[i],1,n,1);
int s = query(1,pos[i],1,n,1);
if (s < n - i)//如果pos[i]后面还有未被删除的点
curpos = getpos(s + 1,1,n,1);
else//如果没有就找第一个未被删除的点
curpos = getpos(1,1,n,1);
}
printf("%I64d\n",ans);
}

return 0;
}


1006 hdu 4325 http://acm.hdu.edu.cn/showproblem.php?pid=4325

/article/7104919.html

pku Sliding Window http://poj.org/problem?id=2823

题解:/article/7104951.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: