1. 程式人生 > >【線段樹】【資料結構】四校聯考1024T3

【線段樹】【資料結構】四校聯考1024T3

題意

在這裡插入圖片描述

分析:

沒過是因為沒看。。。

這題其實相當水。。。

重新定義一下逆序對:每個點的貢獻為,其後面的,比它小的數的個數。

然後這樣一來,每次排過序之後的點,其後面就不可能有比它小的值了,直接忽略以後排序又排到它的情況。

#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); } }