【線段樹】【資料結構】四校聯考1024T3
阿新 • • 發佈:2018-12-17
題意
分析:
沒過是因為沒看。。。
這題其實相當水。。。
重新定義一下逆序對:每個點的貢獻為,其後面的,比它小的數的個數。
然後這樣一來,每次排過序之後的點,其後面就不可能有比它小的值了,直接忽略以後排序又排到它的情況。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 200010
#define INF 0x3FFFFFFF
using namespace std;
typedef long long ll;
int n,m;
int a[MAXN];
ll f[MAXN],ans;
ll tr[MAXN*4];
void build(int l=1,int r=n,int id=1){
int mid=(l+r)>>1;
if(l==r){
tr[id]=a[l];
return ;
}
build(l,mid,id<<1);
build(mid+1,r,id<<1|1);
tr[id]=min(tr[id<<1],tr[id<<1|1]);
}
ll tree[MAXN] ;
ll find(int x){
int res=0;
while(x){
res+=tree[x];
x-=x&(-x);
}
return res;
}
void add(int x){
while(x<=n){
tree[x]++;
x+=x&(-x);
}
}
int find(int l1,int r1,int val,int l=1,int r=n,int id=1){
if(tr[id]>val)
return -1;
if(l==r){
tr[id]=INF;
return l;
}
int res=- 1;
int mid=(l+r)>>1;
if(l1<=mid){
res=find(l1,r1,val,l,mid,id<<1);
tr[id]=min(tr[id<<1],tr[id<<1|1]);
if(res!=-1)
return res;
}
if(r1>mid){
res=find(l1,r1,val,mid+1,r,id<<1|1);
tr[id]=min(tr[id<<1],tr[id<<1|1]);
if(res!=-1)
return res;
}
return res;
}
int main(){
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
SF("%d%d",&n,&m);
for(int i=1;i<=n;i++)
SF("%d",&a[i]);
for(int i=n;i>=1;i--){
if(a[i]!=1)
f[i]=find(a[i]-1);
ans+=f[i];
add(a[i]);
}
build();
PF("%lld ",ans);
int t;
for(int i=1;i<=m;i++){
SF("%d",&t);
int id=find(t,n,a[t]);
while(id!=-1){
ans-=f[id];
id=find(t,n,a[t]);
}
PF("%lld ",ans);
}
}