HDU4262–Juggler(区间求和&&单点更新)

题目大意

有一个圆形管道,里面有N个球,给定N个球的出圈顺序,最初的时候手的位置是在第一个球的位置,如果一个球的位置刚好是手所在的位置,那么它可以被取出,要求你按照给定的出圈顺序,依次取出N个球,在旋转到目标小球的时候,可以向左旋转,也可以向右旋转,每移动一个单位位置,需要一个单位的花费,要求你计算出最少的花费是多少

题解

如果读懂题目了,那么就很好做了,当时模拟的比赛的时候看了好久题目都没有看懂题,o(╯□╰)o。。。对于每一个位置,用1来表示有球,0来表示没求,用线段树来维护前缀和即可,每次查找手所在位置之前有多少个球,然后查找目标小球的位置之前有多少个球,这两个操作都是求前缀和,两个值的差的绝对值就是它们两之间的一个距离d,假设当前处理的是第i个球,那么另外一个距离等于:n-i+1-d。选择两者中的小者。然后进行删除操作(单点更新)

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXN 100005
#define lson l,m,s<<1
#define rson m+1,r,s<<1|1
int sumv[MAXN<<2],pos[MAXN];
void PushUp(int s)
{
    sumv[s]=sumv[s<<1]+sumv[s<<1|1];
}
void build(int l,int r,int s)
{
    if(l==r) {
        sumv[s]=1;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    PushUp(s);
}
void update(int p,int l,int r,int s)
{
    sumv[s]--;
    if(l==r) return;
    int m=(l+r)>>1;
    if(p<=m) update(p,lson);
    else
        update(p,rson);
}
int query(int ql,int qr,int l,int r,int s)
{
    if(ql<=l&&r<=qr)
        return sumv[s];
    int m=(l+r)>>1,ans=0;
    if(ql<=m) ans+=query(ql,qr,lson);
    if(qr>m) ans+=query(ql,qr,rson);
    return ans;
}
int main(void)
{
    int n,p,a,b,d;
    while(scanf("%d",&n)!=EOF&&n) {
        __int64 sum=0;
        build(1,n,1);
        for(int i=1; i<=n; i++) {
            scanf("%d",&p);
            pos[p]=i;
        }
        p=1;
        for(int i=1; i<=n; i++) {
            a=0;
            b=0;
            if(p-1) a=query(1,p-1,1,n,1);
            if(pos[i]-1) b=query(1,pos[i]-1,1,n,1);
            d=abs(a-b);
            sum+=min(d+1,n-i+2-d);
            update(pos[i],1,n,1);
            p=pos[i];
        }
        printf("%I64d\n",sum);
    }
    return 0;
}

上述方法耗时1156ms,由于题目要求的操作就是查询前缀和以及单点修改,因此可以用树状数组来做,空间消耗和时间消耗都要比用线段树小,耗时只需要390ms

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXN 100005
int c[MAXN],pos[MAXN];
int n;
int lowbit(int x)
{
    return x&-x;
}
void add(int x,int d)
{
    while(x<=MAXN) {
        c[x]+=d;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int ret=0;
    while(x>0) {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
int main(void)
{
    int a,b,d,p;
    while(scanf("%d",&n)!=EOF&&n) {
        __int64 ans=0;
        memset(c,0,sizeof(c));
        for(int i=1; i<=n; i++) {
            scanf("%d",&p);
            pos[p]=i;
            add(i,1);
        }
        int p=1;
        for(int i=1; i<=n; i++) {
            a=sum(p-1);
            b=sum(pos[i]-1);
            d=abs(a-b);
            ans+=min(d+1,n-i+2-d);
            add(pos[i],-1);
            p=pos[i];
        }
        printf("%I64d\n",ans);
    }
}
 
原文地址:https://www.cnblogs.com/zjbztianya/p/3092121.html