BZOJ 3295 [Cqoi2011]动态逆序对
来源:互联网 发布:pm2.5数据接口 编辑:程序博客网 时间:2024/06/05 03:55
首先预处理,对于一个输入的数列求逆序对个数利用树状数组nlogn即可解决。
然后考虑删点的问题。每次删点需要在总ans中删去此节点前比此数大的数的个数和之后此数小的个数。
对于当前的节点,如果需要定点查询一段区间中比一定值c大或小的点的个数,只需要在线段树(或平衡树)上操作即可。而对于这道题,需要讨论每个点,即每个点均需建立一棵线段树。每次查询之后需要在每棵线段树上进行修改操作,单次复杂度logn,每棵则为nlogn,m次则为O(mnlogn),很明显时间无法接受,空间也无法接受,于是可以用树状数组优化。
从另一个方面考虑:如果不考虑查询的是一个区间(即不具有最大或最小值的限定)树状数组通过lowbit记录一条删除的路径,路径上每个点-1,下次查询时沿路径累加即可修正ans;而如果有最大最小值的范围限定,则需要利用线段树(或平衡树)查询。每个节点均需要一棵树支持区间查询,由此进行树套树。
树状数组套主席树
Time:4100 ms
Memory:115672 kb
#include<iostream>#include<cstdlib>#include<cstdio>#include<algorithm>#include<cstring> using namespace std; const int maxn=160005; struct tree{ int lson,rson,val;}t[maxn*60]; int n,m,cnt;long long ans;int f[maxn];int c[maxn];int s[maxn]; void build_init(int &ro,int l,int r){ ro=++cnt; if(l==r)return; int mid=l+r>>1; build_init(t[ro].lson,l,mid); build_init(t[ro].rson,mid+1,r);}void build_seg(int &ro,int pos,int val,int l,int r){ if(!ro)ro=++cnt; t[ro].val+=val; if(l==r)return; int mid=l+r>>1; if(pos<=mid)build_seg(t[ro].lson,pos,val,l,mid); else build_seg(t[ro].rson,pos,val,mid+1,r);}int query_seg(int ro,int maxi,int l,int r){ if(r==maxi)return t[ro].val; int mid=l+r>>1; if(mid>=maxi)return query_seg(t[ro].lson,maxi,l,mid); return query_seg(t[ro].rson,maxi,mid+1,r)+t[t[ro].lson].val;}void update_tree(int x,int pos,int val){ int tmp; for(int i=x;i<=n;i+=i&-x) build_seg(c[i],pos,val,1,n);}long long query_tree(int x,int maxi){ long long res=0; for(int i=x;i;i-=i&-i) res+=query_seg(c[i],maxi,1,n); return res;}void update(int x){ for(int i=x;i<=n;i+=i&-i)s[i]++;}int query(int x){ int res=0; for(int i=x;i;i-=i&-i)res+=s[i]; return res;}long long getans(int pos,int a){ return query_tree(pos,n)-query_tree(pos,a)+query_tree(n,a)-query_tree(pos,a);}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int a; scanf("%d",&a); f[a]=i; update_tree(i,a,1); update(a); ans+=query(n)-query(a); } for(int i=1;i<=m;i++) { printf("%lld\n",ans); int a; scanf("%d",&a); update_tree(f[a],a,-1); ans-=getans(f[a],a); }}
树状数组套treap
Time:10376 ms
Memory:38152 kb
注意可以建立一个空节点null,将NULL替换成null避免因为访问空指针而RE。
#include<iostream>#include<cstdlib>#include<cstdio>#include<algorithm>#include<cstring> using namespace std; const int maxn=160005; struct node{ int rank,val,size; node *son[2]; bool cmp(int val_) { return val<val_; } }Tnull,*null=&Tnull; int n,m,cnt;long long ans;int f[maxn];node* c[maxn];int s[maxn]; node* newnode(node *&o,int val_){ o=new node; o->son[0]=o->son[1]=null; o->rank=rand(); o->val=val_; o->size=1;}void maintain(node *o){ o->size=1; if(o->son[0]!=null)o->size+=o->son[0]->size; if(o->son[1]!=null)o->size+=o->son[1]->size;}void rotate(node *&o,bool d){ node *p=o->son[d];o->son[d]=p->son[d^1];p->son[d^1]=o; maintain(o);maintain(p);o=p;}void insert(node *&o,int val){ if(o==null)o=newnode(o,val); else { bool d=o->cmp(val); insert(o->son[d],val); if(o->son[d]->rank > o->rank) rotate(o,d); } maintain(o);}void del(node *&o,int val){ if(o->val==val) { node *p=o; if(o->son[0]!=null&&o->son[1]!=null) { bool d=o->son[0]->rank < o->son[1]->rank; rotate(o,d); del(o->son[d^1],val); } else { if(o->son[0]!=null)o=o->son[0]; else o=o->son[1]; delete p; } } else { bool d=o->cmp(val); del(o->son[d],val); } if(o!=null)maintain(o);} int count(node *o,int maxi){ if(o==null)return 0; if(maxi>o->val)return o->son[0]->size+1+count(o->son[1],maxi); return count(o->son[0],maxi)+(maxi==o->val);}void update_tree(int x,int pos){ for(int i=x;i<=n;i+=i&-i) { if(!c[i])newnode(c[i],pos); else insert(c[i],pos); }}void delete_tree(int x,int pos){ for(int i=x;i<=n;i+=i&-i) del(c[i],pos);}long long query_tree(int x,int maxi){ long long res=0; for(int i=x;i;i-=i&-i) res+=count(c[i],maxi); return res;}void update(int x){ for(int i=x;i<=n;i+=i&-i)s[i]++;}int query(int x){ int res=0; for(int i=x;i;i-=i&-i)res+=s[i]; return res;}long long getans(int pos,int a){ return query_tree(pos,n)-query_tree(pos,a)+query_tree(n,a)-query_tree(pos,a);}int main(){ srand(20170901); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int a; scanf("%d",&a); f[a]=i; update_tree(i,a); update(a); ans+=query(n)-query(a); } for(int i=1;i<=m;i++) { printf("%lld\n",ans); int a; scanf("%d",&a); delete_tree(f[a],a); ans-=getans(f[a],a); }}
阅读全文
0 0
- [BZOJ 3295] Cqoi2011 动态逆序对
- 【BZOJ 3295】 [Cqoi2011]动态逆序对
- BZOJ 3295 [Cqoi2011]动态逆序对
- BZOJ 3295 [CQOI2011] 动态逆序对
- BZOJ 3295: [Cqoi2011]动态逆序对
- 【BZOJ 3295】[Cqoi2011]动态逆序对
- bzoj 3295 [Cqoi2011]动态逆序对
- BZOJ 3295 [Cqoi2011]动态逆序对
- [bzoj]3295: [Cqoi2011]动态逆序对 主席树
- 主席树初探 & bzoj 3295: [Cqoi2011] 动态逆序对 题解
- bzoj 3295: [Cqoi2011]动态逆序对(树套树)
- bzoj 3295: [Cqoi2011]动态逆序对 【cdq分治】
- bzoj 3295: [Cqoi2011]动态逆序对 cdq分治+树状数组
- BZOJ 3295: [Cqoi2011]动态逆序对 分块大法好
- BZOJ 3295 [Cqoi2011] 动态逆序对 CDQ分治题解
- 【BZOJ】3295 [Cqoi2011]动态逆序对 树状数组+线段树
- 3295: [Cqoi2011]动态逆序对
- 3295: [Cqoi2011]动态逆序对
- UVA
- 记录下使用Ambari部署HDP集群的过程
- 洛谷 P2827 蚯蚓
- 嵌入式面试全攻略,记我的一次校招
- POJ2185 最小覆盖矩阵 (二维KMP)
- BZOJ 3295 [Cqoi2011]动态逆序对
- 51 nod 算法马拉松28 先序遍历与后序遍历
- C++类与对象学习
- 数字游戏---巧妙解答
- 文章标题 如何从网上获取图片
- 【Android笔记-异常-1】
- unicode 编码介绍
- 个人/家庭/社会
- 安卓handler初识(二)