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 } 

 

posted on 2022-07-24 15:32  衔白棋子的黑猫  阅读(40)  评论(0)    收藏  举报

导航