P3157 [CQOI2011]动态逆序对 cdq分治

思路:cdq分治(主席树还没看)

提交:\(2\)次(窝\(CE\)了)

题解:

记录询问:操作的时间\(t_i\)(初始存在的数记时间为\(0\)),操作的位置\(p_i\),操作的值\(vl_i\),操作的类型(\(-1\ or\ 1\))。
记录答案:每次只算出这次操作造成的影响并累加到操作时间上(所以第\(0\)时刻算出的即为初始逆序对),做一个前缀和即可求出某一时刻的答案。
如何计算贡献:考虑一个数所形成的逆序对:

  • \(t_i<t_j\)\(p_i<p_j\)\(vl_i>vl_j\)
  • \(t_i<t_j\)\(p_i>p_j\)\(vl_i<vl_j\)
    所以我们需要扫两次:从前往后扫(第一种)然后从后往前扫(第二种)
// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define R register int
#define ll long long
using namespace std;
namespace Fread {
static char buff[1>>15],*S=buff,*T=buff;
inline char gc() {
#ifdef JACK 
  return getchar();
#else 
  return (S==T&&(T=(S=buff)+fread(buff,1,1<<15,stdin),S==T)?EOF:*S++);
#endif
}
inline int g() {
  R ret=0,fix=1; register char ch; while(!isdigit(ch=gc())) fix=ch=='-'?-1:fix;
  do ret=ret*10+(ch^48); while(isdigit(ch=gc())); return ret*fix;
}
} using Fread::gc; using Fread::g;
namespace Luitaryi {
const int N=150010;
int n,m,c[N],p[N];
ll ans[N];
struct node {int t,p,vl,w,rk;
  inline bool operator <(const node& that) const {return p<that.p;}
}a[N],tmp[N];
inline void add(int p,int d) {for(;p<=n;p+=p&-p) c[p]+=d;}
inline int query(int p) {R ret=0; for(;p;p-=p&-p) ret+=c[p]; return ret;}
inline void solve(int l,int r) {
  if(l==r) return; R md=l+r>>1;
  solve(l,md),solve(md+1,r);
  R j=l,i=md+1; for(;i<=r;++i) {
    while(j<=md&&a[j].p<=a[i].p) add(a[j].vl,a[j].w),++j;
    ans[a[i].t]+=a[i].w*(query(n)-query(a[i].vl));
  } for(R i=l;i<j;++i) add(a[i].vl,-a[i].w);
  j=md,i=r; for(;i>md;--i) {
    while(j>=l&&a[j].p>=a[i].p) add(a[j].vl,a[j].w),--j;
    ans[a[i].t]+=a[i].w*query(a[i].vl-1);
  } for(R i=md;i>j;--i) add(a[i].vl,-a[i].w);
  merge(a+l,a+md+1,a+md+1,a+r+1,tmp+l);
  memcpy(a+l,tmp+l,sizeof(node)*(r-l+1));
}
inline void main() {
  n=g(),m=g();
  for(R i=1;i<=n;++i) a[i].w=1,a[i].vl=g(),a[i].p=i,a[i].t=0,a[i].rk=i,p[a[i].vl]=i;
  for(R i=n+1;i<=n+m;++i) a[i].w=-1,a[i].vl=g(),a[i].p=p[a[i].vl],a[i].t=i-n,a[i].rk=i;
  solve(1,n+m);
  for(R i=1;i<=m;++i) ans[i]+=ans[i-1];
  for(R i=0;i<m;++i) printf("%lld\n",ans[i]);
}
}
signed main() {
  Luitaryi::main(); return 0;
}

2019.07.31
还有100天

posted @ 2019-07-31 11:27  LuitaryiJack  阅读(173)  评论(0编辑  收藏  举报