HDU-4217 树状数组的应用

 

目录

思路:

代码:


思路:

如果用数组暴力的话,每次都要删除操作,复杂度过高。

树状数组比较喜欢和前缀和相联系运用。比如逆序对。先对每一个最深层结点复为1,这样find(x)就可以得到x值。如果某个点已被删除,就标记为0,也就是对其-1。这样查询时,如果在该删除值的前面,无影响。在后面,这样第一个肯定就是。

注意:如果一个数的前一个数和后一个数都已经被删除,这时候第一个和为x的才是,后者也为x因为该点为0,加于不加都一样。这就是需要左侧边界的二分搜索;

具体见:https://www.cnblogs.com/kyoner/p/11080078.html

代码:

#include<algorithm>

#include<iostream>

#include<cstring>

#include<string>

#include<queue>

#include<map>

#include<cstdio>

#include<cmath>

#include<stdlib.h>



using namespace std;

typedef long long ll;

const int INF = 0x3f3f3f3f;

const int maxn = 1e6+50;

ll tree[maxn];

int n,m;

inline int lowbit(int x){

       return x&(-x);

}

void add(int x,int v){

       for(;x<=n;x+=lowbit(x)) tree[x] += v;  

}

ll find(int x){

       ll ans = 0;

       for(;x>0;x-=lowbit(x))   ans += tree[x];

       return ans;

}

int get_k(int x){

       int l = 1,r = n;

       int mid,t;

       while(l <= r){

              mid = (l+r)>>1;

              t=find(mid);

              if(t > x){

                     r=mid-1;

              }

              else if(t < x) l=mid+1;

              else{

                     r=mid;

                     if(l==r)   break;

              }

       }

       return r;

}



int main(){

       cin.tie(0);cout.tie(0);

       int t;

       cin >> t;

       int _case = 0;

       while(t--){

              memset(tree,0,sizeof(tree));

              cin >> n >> m;

              for(int i = 1;i <= n;i++)  add(i,1);

              ll k;

              ll ans = 0;

              while(m--){

                     cin >> k;

                     ll rec = get_k(k);

                     ans += rec;

                     add(rec,-1);          

              }

              printf("Case %d: %lld\n",++_case,ans);

       }

       return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值