树套树||CDQ分治
感觉树套树更好想啊,直接无脑减就行,然而我的树套树几个月之前就打出来了,现在还没调出来……
还是CDQ好调,但是思路并不好想。我们把删除视作倒这插入,没有被删除的就视作最先插入的,于是每个操作就有了时间,位置,数值三元组,首先按时间排序,递归向下,然后在本层处理跨mid的情况:只考虑左区间对右区间的影响,至于区间内的已经递归下去了。将左右区间按位置排序,现在左边的t一定小于右边,用两个单调指针保证左边的位置小于右边(然而本题要扫两遍,第二变要保证左边位置大于右边),然后按第三维扔到权值树状数组,对于右区间查询更新答案即可。
对于本题,要查询的就是一个数左边比他大的数和右边比他小的数。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #define int long long 6 #define ma(x) memset(x,0,sizeof(x)) 7 #define MAXN 100010 8 using namespace std; 9 struct al 10 { 11 int t,s,loc,ans; 12 #define t(x) ca[x].t 13 #define s(x) ca[x].s 14 #define loc(x) ca[x].loc 15 #define ans(x) ca[x].ans 16 friend bool operator == (al a,al b) 17 {return a.t==b.t&&a.s==b.s&&a.ans==b.ans;} 18 }ca[MAXN]; 19 int n,m,sum,a[MAXN],ni[MAXN]; 20 int C[MAXN],bel[MAXN]; 21 #define lowbit(x) ((x)&(-(x))) 22 void add(int x,int y) 23 {while(x<=n){C[x]+=y;x+=lowbit(x);}} 24 int ask(int x) 25 {int ans=0;while(x){ans+=C[x];x-=lowbit(x);}return ans;} 26 bool cmp1(al a,al b){return a.t<b.t;} 27 bool cmp2(al a,al b){return a.loc<b.loc;} 28 bool cmp3(al a,al b){return a.t>b.t;} 29 void CDQ(int l,int r) 30 { 31 if(l==r)return; 32 int mid=(l+r)>>1; 33 CDQ(l,mid),CDQ(mid+1,r); 34 sort(ca+l,ca+mid+1,cmp2); 35 sort(ca+mid+1,ca+r+1,cmp2); 36 int j=l; 37 for(int i=mid+1;i<=r;i++) 38 { 39 while(j<=mid&&loc(j)<loc(i))add(s(j),1),j++; 40 ans(i)+=ask(n)-ask(s(i)); 41 } 42 for(int i=l;i<j;i++)add(s(i),-1); 43 j=mid; 44 for(int i=r;i>mid;i--) 45 { 46 while(j>=l&&loc(j)>loc(i))add(s(j),1),j--; 47 ans(i)+=ask(s(i)-1); 48 } 49 for(int i=mid;i>j;i--)add(s(i),-1); 50 } 51 signed main() 52 { 53 // freopen("in.txt","r",stdin); 54 55 cin>>n>>m;int tem=n,tt; 56 for(int i=1;i<=n;i++) 57 {cin>>s(i);loc(i)=i;bel[s(i)]=i;} 58 for(int i=1;i<=m;i++) 59 {cin>>tt,t(bel[tt])=tem--;} 60 for(int i=1;i<=n;i++) 61 if(!t(i))t(i)=tem--; 62 sort(ca+1,ca+n+1,cmp1); 63 CDQ(1,n); 64 sort(ca+1,ca+n+1,cmp3); 65 int eans=0; 66 for(int i=1;i<=n;i++)eans+=ans(i); 67 for(int i=1;i<=m;i++) 68 { 69 cout<<eans<<endl; 70 eans-=ans(i); 71 } 72 }