bzoj3295[Cqoi2011]动态逆序对(cdq分治||可持久化线段树)
来源:互联网 发布:数据报表图片 编辑:程序博客网 时间:2024/06/05 16:25
题目链接:点这里!!!
3295: [Cqoi2011]动态逆序对
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3043 Solved: 967
[Submit][Status][Discuss]
Description
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4
1
5
3
4
2
5
1
4
2
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
HINT
N<=100000 M<=50000
做法1:cdq分治
1、首先我们看到求逆序对,很容易想到用树状数组去求逆序对,这里在有修改的情况下,我们一样用树状数组来做,只是再加上cdq分治。
2、首先我们倒过来做,把删除看成添加操作。比如例题:它的添加顺序是(数值):3(没有被删除的数先添加)、2、4、1、5。
3、然后我们来定义一个数组a,三个属性id(添加操作的顺序),val(数值的大小),pv(在序列里的位置)。
4、按照id来排序。 然后我们对val来分治,用pv来更新和求值。
5、注意要更新两次和求值两次,具体看代码,再叠加起来就可。
代码:
#include<cstdio>#include<cstring>#include<iostream>#include<sstream>#include<algorithm>#include<vector>#include<bitset>#include<set>#include<queue>#include<stack>#include<map>#include<cstdlib>#include<cmath>#define PI 2*asin(1.0)#define LL long long#define pb push_back#define pa pair<int,int>#define clr(a,b) memset(a,b,sizeof(a))#define lson lr<<1,l,mid#define rson lr<<1|1,mid+1,r#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)#define key_value ch[ch[root][1]][0]C:\Program Files\Git\binconst int MOD = 1E9+7;const LL N = 1E5+15;const int maxn = 1e4+1000;const int letter = 130;const int INF = 1e17;const double pi=acos(-1.0);const double eps=1e-8;using namespace std;inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}int n,k,val[N],c[N],vis[N],pp[N];LL ans[N];vector<int>ps;struct node{ int id,val,pv;}a[N],b[N];bool cmp(node a,node b){ return a.id<b.id;}int lowbit(int x){return x&(-x);}void update(int i,int v){ for(int x=i;x<=n;x+=lowbit(x)) pp[x]+=v;}int getsum(int i){ int ans=0; for(int x=i;x;x-=lowbit(x)) ans+=pp[x]; return ans;}void solve(int l,int r){ if(l==r) return; int mid=(l+r)>>1;/// val for(int i=l;i<=r;i++){ if(a[i].val<=mid) update(a[i].pv,1); else ans[a[i].id]+=1ll*(getsum(n)-getsum(a[i].pv)); } for(int i=l;i<=r;i++) if(a[i].val<=mid) update(a[i].pv,-1); for(int i=l;i<=r;i++){ if(a[i].val>mid) update(a[i].pv,1); else ans[a[i].id]+=1ll*getsum(a[i].pv-1); } for(int i=l;i<=r;i++) if(a[i].val>mid) update(a[i].pv,-1); int ll=l; for(int i=l;i<=r;i++) if(a[i].val<=mid) b[ll++]=a[i]; for(int i=l;i<=r;i++) if(a[i].val>mid) b[ll++]=a[i]; for(int i=l;i<=r;i++) a[i]=b[i]; solve(l,mid); solve(mid+1,r);}int main(){ ps.clear(); int x; n=read(),k=read(); for(int i=1;i<=n;i++){ a[i].val=read(),a[i].pv=i; c[a[i].val]=i; } for(int i=1;i<=k;i++){ x=read(); vis[c[x]]=1; ps.pb(c[x]); } int cnt=0; for(int i=1;i<=n;i++){ if(!vis[i]) a[i].id=++cnt; } for(int i=ps.size()-1;i>=0;i--) a[ps[i]].id=++cnt; sort(a+1,a+cnt+1,cmp); solve(1,n); for(int i=1;i<=n;i++){ ans[i]+=ans[i-1]; } for(int i=k;i>=1;i--){ printf("%lld\n",ans[n-k+i]); } return 0;}/*5 41 5 3 4 25 1 4 25 55 4 3 2 15 4 3 2 1*/
做法2:可持久化线段树
这道题做了一天,超了一天的内存,傻逼了。= =,然后优化一下就过了,一脸蒙逼。
1、注意一下数据范围:n<=100000 m<=50000。一开始做的时候我用的是n个数去维护可持久化线段树,各种超内存。
2、仔细想了一下我们有n-m个数没有变过,所以我们离线处理。其他m个点,插入用可持久化线段树即可。
#include<cstdio>#include<cstring>#include<iostream>#include<sstream>#include<algorithm>#include<vector>#include<bitset>#include<set>#include<queue>#include<stack>#include<map>#include<cstdlib>#include<cmath>#define PI 2*asin(1.0)#define LL long long#define pb push_back#define pa pair<int,int>#define clr(a,b) memset(a,b,sizeof(a))#define lson lr<<1,l,mid#define rson lr<<1|1,mid+1,r#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)#define key_value ch[ch[root][1]][0]C:\Program Files\Git\binconst int MOD = 1E9+7;const LL N = 1E5+15;const int maxn = 1e4+1000;const int letter = 130;const int INF = 1e17;const double pi=acos(-1.0);const double eps=1e-8;using namespace std;inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}int n,k,val[N],w[N],c[N],d[N];int sum[N*100],ls[N*100],rs[N*100],root[N],siz,ps[N],vis[N];int pl[50],pr[50],aa,bb;int vl[N],vr[N];vector<LL>pp;int lowbit(int x){ return x&(-x);}void update(int i,int val){ for(int x=i;x<=n;x+=lowbit(x)) ps[x]+=val;}int getsum(int i){ int ans=0; for(int x=i;x>0;x-=lowbit(x)) ans+=ps[x]; return ans;}void insert(int ll,int rr,int x,int &y,int v,int add){ y=++siz; sum[y]=sum[x]+add; ls[y]=ls[x],rs[y]=rs[x]; if(ll==rr) return; int mid=(ll+rr)>>1; if(v<=mid) insert(ll,mid,ls[x],ls[y],v,add); else insert(mid+1,rr,rs[x],rs[y],v,add);}int query(int l,int r,int w){ ///1 n w int suml=0,sumr=0; if(l==r){ for(int i=0;i<aa;i++) suml+=sum[pl[i]]; for(int i=0;i<bb;i++) sumr+=sum[pr[i]]; return sumr-suml; } int mid=(l+r)>>1; for(int i=0;i<aa;i++) suml+=sum[ls[pl[i]]]; for(int i=0;i<bb;i++) sumr+=sum[ls[pr[i]]]; if(w<=mid){ for(int i=0;i<aa;i++) pl[i]=ls[pl[i]]; for(int i=0;i<bb;i++) pr[i]=ls[pr[i]]; return query(l,mid,w); } else { for(int i=0;i<aa;i++) pl[i]=rs[pl[i]]; for(int i=0;i<bb;i++) pr[i]=rs[pr[i]]; return sumr-suml+query(mid+1,r,w); }}void init(){ pp.clear(); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ val[i]=read(); w[val[i]]=i; ///at } for(int i=1;i<=k;i++){ int x; x=read(); d[i]=x; c[i]=w[x]; vis[c[i]]=1; } LL ans=0; int cnt=0; for(int i=1;i<=n;i++){ if(!vis[i]){ ///no update(val[i],1); ans+=1ll*(cnt-getsum(val[i]-1)); cnt++; } else { /// shanchu vl[i]=cnt-getsum(val[i]-1); } } cnt=0; clr(ps,0); for(int i=n;i>=1;i--){ if(!vis[i]){ update(val[i],1); } else { vr[i]=getsum(val[i]-1); } } clr(ps,0); for(int i=k;i>=1;i--){ aa=bb=0; for(int j=c[i];j<=n;j+=lowbit(j)) insert(1,n,root[j],root[j],d[i],1); for(int j=c[i]-1;j;j-=lowbit(j)) pr[bb++]=root[j]; update(c[i],1); ans+=1ll*((LL)getsum(c[i]-1)-(LL)query(1,n,d[i]-1)+vl[c[i]]); aa=bb=0; for(int j=c[i];j;j-=lowbit(j)) pl[aa++]=root[j]; for(int j=n;j;j-=lowbit(j)) pr[bb++]=root[j]; ans+=1ll*(vr[c[i]]+query(1,n,d[i]-1)); pp.pb(ans); } for(int i=pp.size()-1;i>=0;i--) printf("%lld\n",pp[i]);}int main(){ // freopen("input.txt","r",stdin); // freopen("out.txt","w",stdout); init(); return 0;}/*5 41 5 3 4 25 1 4 210 510 9 8 7 6 5 4 3 2 15 4 3 2 15 35 4 3 2 13 2 1*/
0 0
- bzoj3295[Cqoi2011]动态逆序对(cdq分治||可持久化线段树)
- [BZOJ3295][Cqoi2011]动态逆序对(树状数组套线段树||cdq分治)
- [BZOJ3295] [Cqoi2011]动态逆序对 && CDQ分治
- BZOJ3295: [Cqoi2011]动态逆序对(CDQ分治)
- bzoj3295 [Cqoi2011]动态逆序对(CDQ分治)
- bzoj3295[Cqoi2011]动态逆序对 cdq分治(树套树/主席树)
- [BZOJ3295] [Cqoi2011]动态逆序对 (树套树)or(CDQ分治)
- CDQ分治——BZOJ3295/Luogu3157 [CQOI2011]动态逆序对
- [BZOJ3295][CQOI2011]动态逆序对-CDQ分治+树状数组
- 【BZOJ3295】动态逆序对,CDQ分治/BIT套权值线段树
- 【BZOJ3295】动态逆序对(CQOI2011)-CDQ分治:三维偏序
- BZOJ3295:[Cqoi2011]动态逆序对 (BIT套treap/CDQ分治+BIT)
- 整体二分&CDQ分治:[BZOJ2527][POI2011] meteors [BZOJ3295][CQOI2011] 动态逆序对
- bzoj3295: [Cqoi2011]动态逆序对 树状数组套线段树
- 【cdq分治】[HYSBZ/BZOJ3295]动态逆序对
- 【bzoj3295】动态逆序对 CDQ分治
- [BZOJ3295]动态逆序对CDQ分治
- 【CDQ分治】[CQOI2011][NKOJ2041]动态逆序对
- 易语言学习第二十五课----CE查找内存
- HashMap实现原理分析
- 产品战略和战术
- MySQL操作命令及运算符
- 自己写一个ajax
- bzoj3295[Cqoi2011]动态逆序对(cdq分治||可持久化线段树)
- 20 Top Things to do after installing Fedora 23
- Android TextView中字体行间距的设置
- C和C++混合编程FAQ
- android 制作.9.png图片
- WEB前端 学习手札
- 面试题2
- tatty
- 容易被忽视的API总结