您的位置:首页 > 其它

【JZOJ5222】【GDOI2018模拟7.12】A

2017-07-12 22:16 369 查看

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 long
using 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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: