bzoj3192: [JLOI2013]删除物品
又是一道玄学乱搞
本来我感觉是写两颗splay然后翻转什么的,后来发现可以乱搞
就是把第一个栈反过来,两个栈拼起来, 然后记录一个分割点,从大到小模拟,移动分割点,中间的经过的没被删除的元素就用树状数组维护下
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,m; LL s[110000]; int lowbit(int x){return x&-x;} void change(int x,int k) { while(x<=105000) { s[x]+=k; x+=lowbit(x); } } int getsum(int x) { int ret=0; while(x>0) { ret+=s[x]; x-=lowbit(x); } return ret; } struct node{int k,id;}a[110000]; bool cmp(node n1,node n2){return n1.k>n2.k;} int lslen,ls[110000]; void LSH() { lslen=m; for(int i=1;i<=m;i++)ls[i]=a[i].k; sort(ls+1,ls+lslen+1); lslen=unique(ls+1,ls+lslen+1)-ls-1; for(int i=1;i<=m;i++) a[i].k=lower_bound(ls+1,ls+lslen+1,a[i].k)-ls; }//init int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); n=read(),m=read(); for(int i=1;i<=n;i++) a[n-i+1].k=read(), a[i].id=i; for(int i=n+1;i<=n+m;i++) a[i].k=read(), a[i].id=i; m+=n;n++;LSH(); sort(a+1,a+m+1,cmp); //n表示第n-1个位置和第n个位置不在一个栈中 for(int i=1;i<=m;i++)change(i,1); LL ans=0; for(int i=1;i<m;i++) { if(a[i].id<n-1) { ans+=getsum(n-1)-getsum(a[i].id); } else if(n<a[i].id) { ans+=getsum(a[i].id-1)-getsum(n-1); } change(a[i].id,-1); n=a[i].id+1; } printf("%lld\n",ans); return 0; }
pain and happy in the cruel world.