您的位置:首页 > 其它

uva11990 - ``Dynamic'' Inversion(线段树套树状数组+分块)

2015-05-20 08:29 543 查看
题意:给出一个1,2,...,n的一个排列,然后删除一些数,每次删除之前,输出当前的逆序对数

思路:维护两个值,tree表示当前层,每一个线段树区间的树状数组,维护已经删除了多少个数,order维护,每一个线段树区间排好序的数列

每次输出答案后,进行更新,首先把当前这个数位置之前大于他的减掉,后面小于他的减掉,然后把这个位置标记为删除掉过

/*
 *线段树套树状数组
 *gaolee
 */
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=200010;
int N,M;
int tree[30][maxn];
int order[30][maxn];
int X[maxn],tmp[maxn];
LL ans;
void add(int *s,int x,int n,int val)
{
    while(x<=n)
    {
        s[x]+=val;
        x+=(x&(-x));
    }
}
int getsum(int *s,int x,int n)
{
    int sum=0;
    while(x>n)
    {
        sum+=s[x];
        x-=(x&(-x));
    }
    return sum;
}
void build(int o,int l,int r,int d)
{
    for(int i=l;i<=r;i++)
        order[d][i]=order[d-1][i],tree[d][i]=0;
    if(l==r)return ;
    int mid=(l+r)>>1;
    build(o<<1,l,mid,d+1);
    build(o<<1|1,mid+1,r,d+1);
    sort(order[d]+l,order[d]+r+1);
}
int bitser(int a,int b,int d,int v)
{
    int l = a,r = b,md;
    while(l < r){
        md = (l + r) >> 1;
        if(order[d][md]>=v)r = md;
        else l = md + 1;
    }
    if(order[d][l]>v)--l;
    return l;
}
void query(int o,int l,int r,int q1,int q2,int x,int d,int flag)
{
    if(q1<=l&&r<=q2)
    {

        int k=lower_bound(order[d]+l,order[d]+r+1,x)-order[d];
        if(order[d][k]>x||k>r)k--;
        int t=getsum(tree[d],k,l-1);
        if(!flag)
        {
            k=r-k;
            t=getsum(tree[d],r,l-1)-t;
        }
        else k-=l-1;
        ans-=k-t;
        return ;
    }
    if(l>=r)return ;
    int mid=(l+r)>>1;
    if(q1<=mid)query(o<<1,l,mid,q1,q2,x,d+1,flag);
    if(q2>mid)query(o<<1|1,mid+1,r,q1,q2,x,d+1,flag);
}
void update(int o,int l,int r,int pos,int x,int d)
{
    if(l==r)
    {
        add(tree[d],l,r,1);
        return ;
    }
    if(l>=r)return ;
    int mid=(l+r)>>1;
    if(pos<=mid)update(o<<1,l,mid,pos,x,d+1);
    else update(o<<1|1,mid+1,r,pos,x,d+1);
    int k=lower_bound(order[d]+l,order[d]+r+1,x)-order[d];
    add(tree[d],k,r,1);
}
int main()
{
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        ans=0;
        memset(tmp,0,sizeof(tmp));
        for(int i=1;i<=N;i++)
        {
            scanf("%d",&order[0][i]);
            X[order[0][i]]=i;
            ans+=(i-1-getsum(tmp,order[0][i],0));
            add(tmp,order[0][i],N,1);
        }
        build(1,1,N,1);
        while(M--)
        {
            int x;
            scanf("%d",&x);
            printf("%lld\n",ans);
            if(ans)
            {
                query(1,1,N,1,X[x]-1,x,1,0);
                query(1,1,N,X[x]+1,N,x,1,1);
                update(1,1,N,X[x],x,1);
            }
        }
    }
    return 0;
}


目前分块做法处于WA阶段,不知道错哪了

/*
 *分块
 *gaolee
 */
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=200010;
const int maxm=4010;
int N,M;
int A[maxn],pos[maxn],tmp[maxn];
int size;
int block[maxm][maxm];
int st[maxn],vis[maxn];
LL ans;
void add(int *s,int x,int n,int val)
{
    while(x<=n)
    {
        s[x]+=val;
        x+=(x&(-x));
    }
}
int getsum(int *s,int x,int n)
{
    int sum=0;
    while(x>n)
    {
        sum+=s[x];
        x-=(x&(-x));
    }
    return sum;
}
void init()
{
    size=int(sqrt(N));
    int num=0,j=0;
    for(int i=0;i<N;i++)
    {
        block[num][j]=A[i];
        if(++j==size){num++,j=0;}
    }
    for(int i=0;i<num;i++)sort(block[i],block[i]+size);
    if(j)sort(block[num],block[num]+j);
    for(int i=0;i<=num;i++)st[i]=i*size;
}
void QueryMax(int l,int r,int x)
{
    int xpos=l/size,ypos=r/size;
    if(xpos==ypos)
    {
        for(int i=l;i<=r;i++)
            if(!vis[i]&&A[i]>x)ans--;
    }
    else
    {
        for(int i=l;i<(xpos+1)*size;i++)
            if(!vis[i]&&A[i]>x)ans--;
        for(int i=ypos*size;i<=r;i++)
            if(!vis[i]&&A[i]>x)ans--;
        for(int i=xpos+1;i<ypos;i++)
            if(st[i]<(i+1)*size)
                ans-=(i+1)*size-(lower_bound(block[i]+st[i],block[i]+size,x)-block[i]);
    }
}
void QueryMin(int l,int r,int x)
{
    int xpos=l/size,ypos=r/size;
    if(xpos==ypos)
    {
        for(int i=l;i<=r;i++)
            if(!vis[i]&&A[i]<x)ans--;
    }
    else
    {
        for(int i=l;i<(xpos+1)*size;i++)
            if(!vis[i]&&A[i]<x)ans--;
        for(int i=ypos*size;i<=r;i++)
            if(!vis[i]&&A[i]<x)ans--;
        for(int i=xpos+1;i<ypos;i++)
            if(st[i]<(i+1)*size)
                ans-=lower_bound(block[i]+st[i],block[i]+size,x)-block[i]-st[i];
    }
}
void update(int x,int val)
{
    int bpos=x/size;
    int p=0;
    while(p<size&&block[bpos][p]<val)p++;
    if(p==size)p--;block[bpos][p]=-1;
    while(p>0&&block[bpos][p]<block[bpos][p-1])
    {
        swap(block[bpos][p],block[bpos][p-1]),p--;
    }
    st[bpos]++;
}
int main()
{freopen("in.txt","r",stdin);
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        ans=0;
        memset(tmp,0,sizeof(tmp));
        for(int i=1;i<=N;i++)
        {
            scanf("%d",&A[i]);
            ans+=(i-1-getsum(tmp,A[i],0));
            add(tmp,A[i],N,1);
        }
        for(int i=0;i<N;i++)
        {
            A[i]=A[i+1];
            A[i]--;
            pos[A[i]]=i;
        }
        memset(vis,0,sizeof(vis));
        init();
        while(M--)
        {
            int x;
            scanf("%d",&x);
            x--;
            printf("%lld\n",ans);
            int X=pos[x]/size;
            if(ans)
            {
                if(X*size-1>0)QueryMax(0,X*size-1,x);
                if((X+1)*size<N)QueryMin((X+1)*size,N-1,x);
                for(int i=X*size;i<pos[x];i++)
                    if(!vis[i]&&A[i]>x)ans--;

                for(int i=pos[x]+1;i<min((X+1)*size,N);i++)
                    if(!vis[i]&&A[i]<x)ans--;
                update(pos[x],x);
                vis[pos[x]]=1;
            }
        }
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: