【JZOJ5222】【GDOI2018模拟7.12】A

来源:互联网 发布:大数据研究方向有哪些 编辑:程序博客网 时间:2024/06/01 10:18

Description

这里写图片描述
注意:题意有误,IQ小于等于的都会听从指挥

Data Constraint

这里写图片描述

Solution

这道题,有两个坑,首先,IQ小于等于的都会听从指挥,这在做题时居然没讲,居然还有人AC了!!!其次,士兵的IQ可以为0,这小学都没上就去打仗了吧?
然后我用暴力过了^^但后来还是打了遍正解。
下面讲一下正解。
我们考虑当一个操作在x时,我们发现IQ大于a[x]的其往后的逆序对是不变的,而IQ小于等于a[x]的其往后的逆序对会变为0。所以这就意味着x只会对IQ小于a[x]的后方有影响。换句话说,一次操作会造成影响的:1、标号必须大于x 2、IQ必须小于等于a[x]这是个二维偏序。而且被操作过的点逆序对数将永远变为0。
问题转化成该如何求每个士兵变为0的最早时间。
所以我们先对操作按x从小到大进行排序,维护一个权值线段树维护每个权值最早的修改时间,然后枚举操作,每次操作由x右移至x’时,序列上x到x’-1的士兵往后都不会再被执行操作,所以我们在权值线段树上对应的a取出它的最早修改时间并计入数组。那样往后对这些权值的修改时间进行修改时,也与这些士兵的修改时间无关。于是我们就得出了每个士兵变为0的最早时间。最后我们按修改时间对士兵进行排序,按询问时间统计逆序对数量。

Code

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long longusing namespace std;const int maxn=1e5+5;struct code{    ll a,b;}c[maxn],b[maxn];ll a[maxn],f[maxn*4],g[maxn];ll n,m,i,t,j,k,l,x,y,z,ans,num,p;bool cmp(code x,code y){    return x.a<y.a;}void insert(ll x){    while (x<=n) f[x]++,x+=(x&(-x));}ll find(int x){    ll t=0;    while (x>0) t+=f[x],x-=(x&(-x));    return t;}void change(int l,int r,int v,int x,int y){    int mid=(l+r)/2;    if (f[v]!=p && l!=r){        f[v*2]=min(f[v*2],f[v]);f[v*2+1]=min(f[v*2+1],f[v]);f[v]=p;    }    if (l>=x && r<=y){        f[v]=min(z,f[v]);        return;    }    if (l<=y && mid>=x) change(l,mid,v*2,x,y);    if (mid<y && r>=x) change(mid+1,r,v*2+1,x,y);}void find1(int l,int r,int v,int x){    int mid=(l+r)/2;    if (f[v]!=p && l!=r){        f[v*2]=min(f[v*2],f[v]);f[v*2+1]=min(f[v*2+1],f[v]);f[v]=p;    }    if (l==r){        t=f[v];return;    }    if (x<=mid)find1(l,mid,v*2,x);    else find1(mid+1,r,v*2+1,x);}int main(){//  freopen("data.in","r",stdin);freopen("data.out","w",stdout);    scanf("%lld%lld",&n,&m);    for (i=1;i<=n;i++)        scanf("%lld",&a[i]),c[i].a=a[i],c[i].b=i;    sort(c+1,c+n+1,cmp);num=0;c[0].a=-1;    for (i=1;i<=n;i++){        if (c[i].a>c[i-1].a) ++num;        a[c[i].b]=num;    }    for (i=n;i>=1;i--)        g[i]=find(a[i]-1),ans+=g[i],insert(a[i]);    printf("%lld\n",ans);    for (i=1;i<=m;i++)        scanf("%d",&c[i].a),c[i].b=i;    sort(c+1,c+m+1,cmp);    memset(f,127,sizeof(f));p=f[1];j=1;     for (i=1;i<=m;i++){         while (j<c[i].a) find1(1,n,1,a[j]),b[j].a=t,b[j].b=g[j],j++;        z=c[i].b,change(1,n,1,1,a[c[i].a]);    }     while (j<=n) find1(1,n,1,a[j]),b[j].a=t,b[j].b=g[j],j++;    sort(b+1,b+n+1,cmp);j=1;    for (i=1;i<=m;i++){        while (b[j].a<=i && j<=n) ans-=b[j++].b;        printf("%lld\n",ans);    }}
原创粉丝点击