首页 > 代码库 > 多校第十场:HDU 4973 树状数组+前缀+二分
多校第十场:HDU 4973 树状数组+前缀+二分
思路:比赛的时候看到这题感觉是线段树或者树状数组,但是因为要区间加倍,然后不知所措了,想了好久也不知道怎么把那个加倍的数怎么处理,然后就一直想第一道题了就没管这题了。虽然之前也做过这种类型的树状数组,不过这题确实是比较机智,把树状数组用得是非常爽。
sum[i]是树状数组的前缀和,cnt[i]表示第i个数共有多少个数。
更新加倍过程:我们让(l,r)这个区间加倍的时候,二分树状数组找到l所对应的数,找到r对应的数,单点更新这两个数,为什么要单点更新这两个数呢?因为比如:1 1 1 2 2 2 3 3 3 4 4这个序列,令(l,r)=(2,8),2位置查找到1这个数,但是是从第2个位置开始的,所以只包含了两个1;8位置也只包含了两个3,并不是全部包含了所有的1和3,所以这端点位置为什么要单独更新就是这个原因。然后区间更新他们之间的数,比如上面这个序列,更新1和3之间的数就是2,2的所有数即总共3个数肯定是要全部加倍的。
查找也是一样。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #include<bitset> #define mem(a,b) memset(a,b,sizeof(a)) #define lson i<<1,l,mid #define rson i<<1|1,mid+1,r #define llson j<<1,l,mid #define rrson j<<1|1,mid+1,r #define INF 0x7fffffff #define maxn 50005 typedef long long ll; typedef unsigned long long ull; using namespace std; ll sum[maxn],cnt[maxn]; int n,m; ll getsum(int x) { ll ans=0; for(int i=x; i>0; i-=i&(-i)) ans+=sum[i]; return ans; } void add(int x,ll v) { for(int i=x; i<=n; i+=i&(-i)) sum[i]+=v; } int find(ll v) { int l=1,r=n,mid; while(l<r) { mid=(l+r)>>1; if(getsum(mid)>=v) r=mid; else l=mid+1; } return r; } void update(ll l,ll r) { int L=find(l),R=find(r); if(L==R) { add(L,r-l+1); cnt[L]+=r-l+1; return; } ll LL=getsum(L),RR=getsum(R-1); add(L,LL-l+1),add(R,r-RR);//端点单独更新 cnt[L]+=LL-l+1,cnt[R]+=r-RR; for(int i=L+1;i<R;i++) add(i,cnt[i]),cnt[i]+=cnt[i]; } ll query(ll l,ll r) { int L=find(l),R=find(r); if(L==R) return r-l+1; ll Max=0; Max=getsum(L)-l+1; Max=max(Max,r-getsum(R-1)); for(int i=L+1;i<R;i++) Max=max(Max,cnt[i]); return Max; } int main() { //freopen("1.txt","r",stdin); int t,ii=1; char s[3]; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=0;i<=n;i++) sum[i]=0; for(int i=1;i<=n;i++) add(i,1),cnt[i]=1; printf("Case #%d:\n",ii++); ll l,r; while(m--) { scanf("%s%I64d%I64d",s,&l,&r); if(s[0]=='D') update(l,r); else printf("%I64d\n",query(l,r)); } } return 0; }
多校第十场:HDU 4973 树状数组+前缀+二分
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。