[BZOJ3295][Cqoi2011]动态逆序对(树状数组套线段树||cdq分治)
2016-04-28 14:10
399 查看
题目描述
传送门题解
树状数组套线段树。向序列里插入点显然要比删点方便很多。
首先知道一个点对整个序列的逆序对的贡献其实是这个点前面有多少个比它大的点加上后面有多少个比它小的点。利用树状数组求前缀和的特点可以求出这个点前面有多少个比它小的点和后面有多少个比它小的点,再用区间中的点减一下即可。
那么用线段树来解决区间问题。
线段树表示当前树状数组所代表的范围中元素的个数。那么查询的时候只需要在求前缀的时候把一特定区间累加。
其实这道题也是一道cdq分治挺好的题
同样是插入点,相当于是统计一下每一个点加入会产生多少个新的逆序对
也就是统计一下前面有多少个比它大的和后面有多少个比它小的
按照时间分治,每一次按照位置排序,左右两个指针,然后加入到权值树状数组中查询就行了
代码
树套树#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define LL long long const int max_n=1e5+5; const int max_tree=1e7+5; int n,m,sz; LL ans; int a[max_n],del[max_n],loc[max_n],root[max_n],C[max_n];bool is_del[max_n]; int sum[max_tree],ls[max_tree],rs[max_tree]; LL final[max_n]; inline void update(int now){ sum[now]=sum[ls[now]]+sum[rs[now]]; } inline void modify(int last,int &now,int l,int r,int x,int v){ int mid=(l+r)>>1; if (!now) now=++sz; sum[now]=sum[last]; ls[now]=ls[last]; rs[now]=rs[last]; if (l==r){sum[now]+=v;return;} if (x<=mid) modify(ls[last],ls[now],l,mid,x,v); else modify(rs[last],rs[now],mid+1,r,x,v); update(now); } inline LL query(int now,int l,int r,int lrange,int rrange){ int mid=(l+r)>>1; LL ans=0; if (lrange<=l&&r<=rrange) return (LL)sum[now]; if (lrange<=mid) ans+=query(ls[now],l,mid,lrange,rrange); if (mid+1<=rrange) ans+=query(rs[now],mid+1,r,lrange,rrange); return ans; } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) scanf("%d",&a[i]); for (int i=1;i<=n;++i) loc[a[i]]=i; for (int i=1;i<=m;++i) scanf("%d",&del[i]),is_del[del[i]]=true; for (int i=n;i>=1;--i) if (!is_del[a[i]]){ for (int j=a[i];j>=1;j-=j&(-j)) ans+=query(root[j],1,n,1,n); for (int j=a[i];j<=n;j+=j&(-j)) modify(root[j],root[j],1,n,i,1); for (int j=loc[a[i]];j<=n;j+=j&(-j)) C[j]+=1; } for (int i=m;i>=1;--i){ LL bs=0; if (loc[del[i]]+1<=n) for (int j=del[i];j>=1;j-=j&(-j)) bs+=query(root[j],1,n,loc[del[i]]+1,n); for (int j=del[i];j<=n;j+=j&(-j)) modify(root[j],root[j],1,n,loc[del[i]],1); for (int j=loc[del[i]];j<=n;j+=j&(-j)) C[j]+=1; LL fs=0; if (1<=loc[del[i]]) for (int j=del[i];j>=1;j-=j&(-j)) fs+=query(root[j],1,n,1,loc[del[i]]); int tot=0; for (int j=loc[del[i]];j>=1;j-=j&(-j)) tot+=C[j]; LL fb=(LL)tot-fs; ans+=bs+fb; final[i]=ans; } for (int i=1;i<=m;++i) printf("%lld\n",final[i]); }
cdq分治
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; #define N 100005 #define LL long long int n,m,a ,pos ,ch ; struct data{int loc,val,id;}q ,p ; LL C ,ans ; bool vis ; void add(int loc,LL val) { for (int i=loc;i<=n;i+=i&-i) C[i]+=val; } LL query(int loc) { LL ans=0; for (int i=loc;i>=1;i-=i&-i) ans+=C[i]; return ans; } void cdq(int l,int r) { if (l>=r) return; int mid=(l+r)>>1; cdq(l,mid); cdq(mid+1,r); int pl,pr,tot; pl=l,pr=mid+1,tot=0; while (pr<=r) { while (pl<=mid&&q[pl].loc<=q[pr].loc) { add(q[pl].val,1); ch[++tot]=q[pl].val; ++pl; } ans[q[pr].id]+=query(n)-query(q[pr].val); ++pr; } for (int i=1;i<=tot;++i) add(ch[i],-1); pl=mid,pr=r,tot=0; while (pr>=mid+1) { while (pl>=l&&q[pl].loc>=q[pr].loc) { add(q[pl].val,1); ch[++tot]=q[pl].val; --pl; } ans[q[pr].id]+=query(q[pr].val-1); --pr; } for (int i=1;i<=tot;++i) add(ch[i],-1); int ll=l,rr=mid+1,now=l; while (ll<=mid&&rr<=r) { if (q[ll].loc<q[rr].loc) p[now++]=q[ll++]; else p[now++]=q[rr++]; } while (ll<=mid) p[now++]=q[ll++]; while (rr<=r) p[now++]=q[rr++]; for (int i=l;i<=r;++i) q[i]=p[i]; } int cmpid(data a,data b) { return a.id<b.id; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) scanf("%d",&a[i]),pos[a[i]]=i; for (int i=n;i>=n-m+1;--i) scanf("%d",&q[i].val),q[i].loc=pos[q[i].val],q[i].id=i,vis[q[i].loc]=1; int k=n-m+1; for (int i=1;i<=n;++i) if (!vis[i]) q[--k].loc=i,q[k].val=a[i],q[k].id=k; cdq(1,n); for (int i=1;i<=n;++i) ans[i]+=ans[i-1]; for (int i=n;i>=n-m+1;--i) printf("%lld\n",ans[i]); }
总结
这里的内存1e7差不多,学姐说正常应该开nlog^2n,因为每一个树状数组的节点最多有可能被更新logn次,但是那是上限,一般这样就够了= =相关文章推荐
- tomcat安装并设置开机启动
- Android ImageView的scaleType属性与adjustViewBounds属性
- 记一次中文乱码解决过程
- JAVA接口的一些认识
- Get请求
- 事务并发处理: DB+ORM+逻辑代码
- entity framework discriminator error
- 【iOS】NSNumberFormatter
- nginx启动、重启、关闭
- 思科否认参与美“棱镜”项目
- 在sap系统设置纸张打印格式
- Android 自定义View的一些总结
- 当手机横竖屏切换时,如何有效保证数据完整性
- 原 Servlet生命周期与工作原理
- Spring和MyBatis实现数据的读写分离
- 4.硬链接和软链接
- WHAT YOU DON‘T KNOW,WON‘T HURT YOU.
- 基于Spark SQL 读写Oracle 的简单案例分析常见问题
- 使用AweSocket 收发消息
- 更改linux 防火墙