[BZOJ3295][CQOI2011]动态逆序对 树套树
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3295
观察可得,每一次答案减少的就是,这个数之前比它大的数的个数,这个数之后比它小的数的个数。
所以我们用树状数组来确保这个数前后的区间查询,用权值线段树求其代表的一个区间内比$x$大或小的数的个数。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 int inline readint(){ 7 int Num;char ch; 8 while((ch=getchar())<'0'||ch>'9');Num=ch-'0'; 9 while((ch=getchar())>='0'&&ch<='9') Num=Num*10+ch-'0'; 10 return Num; 11 } 12 void outll(ll x){ 13 if(x>=10) outll(x/10); 14 putchar(x%10+'0'); 15 } 16 int N,M; 17 int pos[100010]; 18 int inline lowbit(int &x){ 19 return x&-x; 20 } 21 int Rt[100010],lc[10000000],rc[10000000],num[10000000],cnt=0; 22 void Insert(int &rt,int l,int r,int x){ 23 if(!rt) rt=++cnt; 24 num[rt]++; 25 if(l==r) return; 26 int mid=l+r>>1; 27 if(x<=mid) Insert(lc[rt],l,mid,x); 28 else Insert(rc[rt],mid+1,r,x); 29 } 30 int Qry(int &rt,int l,int r,int L,int R){ 31 if(!rt) return 0; 32 if(l>=L&&r<=R) return num[rt]; 33 int mid=l+r>>1,ret=0; 34 if(L<=mid) ret=Qry(lc[rt],l,mid,L,R); 35 if(R>mid) ret+=Qry(rc[rt],mid+1,r,L,R); 36 return ret; 37 } 38 void Del(int &rt,int l,int r,int x){ 39 if(!rt) return; 40 num[rt]--; 41 if(l==r) return; 42 int mid=l+r>>1; 43 if(x<=mid) Del(lc[rt],l,mid,x); 44 else Del(rc[rt],mid+1,r,x); 45 } 46 ll Ans=0; 47 int main(){ 48 N=readint(); 49 M=readint(); 50 for(int i=1;i<=N;i++){ 51 int x=readint(); 52 pos[x]=i; 53 for(int j=i;j<=N;j+=lowbit(j)) 54 Insert(Rt[j],1,N,x); 55 if(x!=N) 56 for(int j=i;j>=1;j-=lowbit(j)) 57 Ans+=Qry(Rt[j],1,N,x+1,N); 58 } 59 for(int i=1;i<=M;i++){ 60 outll(Ans); 61 putchar('\n'); 62 int x=readint(); 63 if(x!=N) 64 for(int j=pos[x];j>=1;j-=lowbit(j)) 65 Ans-=Qry(Rt[j],1,N,x+1,N); 66 if(x!=1){ 67 for(int j=N;j>=1;j-=lowbit(j)) 68 Ans-=Qry(Rt[j],1,N,1,x-1); 69 for(int j=pos[x]-1;j>=1;j-=lowbit(j)) 70 Ans+=Qry(Rt[j],1,N,1,x-1); 71 } 72 for(int j=pos[x];j<=N;j+=lowbit(j)) 73 Del(Rt[j],1,N,x); 74 } 75 return 0; 76 }