Beijing 2008 树状数组 ,LA 4329 Ping pong
lrj p197
感觉很妙的一点是,因为ai小于1e5,可以维护ai前面a1~ai-1中小于ai的数的个数的做法:
从前向后扫出现a[j]则赋值v[a[j]]=1,个数即为v[1]+v[2]+v[3]+...v[a[i]-1],即前缀和。
因为要动态修改,查询,单点修改用树状数组即可。记住i如果是左孩子,父节点为i+lowbit[i],如果是右孩子,父节点是i-lowbit[i]。用进位的思想可以帮助理解。
然后修改向右上爬,求和向左上爬。每次操作Olog max(ai)
1 #include<cstdio> 2 #include<algorithm> 3 #include<string.h> 4 using namespace std; 5 const int maxn=2e4+10; 6 const int maxa=1e5+10; 7 int a[maxn],b[maxn]; 8 int v[maxa],rak[maxa]; 9 int lowbit(int x) {return x&-x;} 10 void aadd(int i,int x,int n) 11 { 12 while(i<=n) 13 {v[i]+=x;i+=lowbit(i);} 14 } 15 int ssum(int x) 16 { 17 int ret=0; 18 while(x>0) 19 {ret+=v[x];x-=lowbit(x);} 20 return ret; 21 } 22 int main() 23 { 24 int T; 25 scanf("%d",&T); 26 while(T--) 27 { 28 memset(v,0,sizeof(v)); 29 int n; 30 long long ans=0; 31 scanf("%d",&n); 32 for(int i=1;i<=n;i++) 33 { 34 int x; 35 scanf("%d",&x); 36 a[i]=b[i]=x; 37 } 38 sort(b+1,b+n+1); 39 for(int i=1;i<=n;i++) 40 rak[b[i]]=i; 41 for(int i=1;i<=n;i++) 42 { 43 int rk=rak[a[i]],d=ssum(a[i]); 44 ans+=1ll*(rk-1-d)*(i-1-d)+1ll*d*(n-rk-(i-1-d)); 45 aadd(a[i],1,b[n]); 46 } 47 printf("%lld\n",ans); 48 } 49 return 0; 50 }
浙公网安备 33010602011771号