[2017雅礼7-2]翻卡片 线段树

xiaoxiao2021-02-28  138

对于某张卡片,操作可分为三类: Ta < min(Ai,Bi) < =Tb < max(Ai,Bi) < =Tc 对于Ta操作,没有影响。 对于Tb操作,大的那一面一定朝上。 对于Tc操作,每次都会翻一面。 所以我们只要找到每张卡片对应的最后一次Tb,再计算此之后有多少Tc即可。 权值离散化后,建权值线段树,第一个问题相当于区间最大值,第二个问题相当于有时间顺序的区间和,Tc按从大到小顺序加入,询问Tb到结束的和。时间复杂度O(n log n)

代码:

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=200100; int a[maxn<<2],b[maxn][2],c[maxn],d[maxn<<2],n,m,size; bool mark[maxn]; struct node { int t,id; }last[maxn]; struct tree { tree *ls,*rs; int l,r,mx,sum; tree() { ls=rs=NULL; mx=sum=0; } void update() { mx=max(ls->mx,rs->mx); sum=ls->sum+rs->sum; } void build(int lx,int rx) { l=lx;r=rx; if(l==r) { mx=sum=d[l]; return ; } int mid=(l+r)>>1; (ls=new tree)->build(l,mid); (rs=new tree)->build(mid+1,r); update(); } int qmax(int lx,int rx) { if(lx>rx) return 0; if(l==lx&&r==rx) return mx; int mid=(l+r)>>1; if(rx<=mid) return ls->qmax(lx,rx); else if(lx>mid) return rs->qmax(lx,rx); else return max(ls->qmax(lx,mid),rs->qmax(mid+1,rx)); } void add(int pl) { if(l==r) {sum++; return ;} int mid=(l+r)>>1; if(pl<=mid) ls->add(pl); else rs->add(pl); update(); } int qsum(int lx,int rx) { if(lx>rx) return 0; if(l==lx&&r==rx) return sum; int mid=(l+r)>>1; if(rx<=mid) return ls->qsum(lx,rx); else if(lx>mid) return rs->qsum(lx,rx); else return ls->qsum(lx,mid)+rs->qsum(mid+1,rx); } }; bool cmp(node a,node b) { return a.t>b.t; } int main() { freopen("card.in","r",stdin); freopen("card.out","w",stdout); cin>>n>>m; memset(mark,0,sizeof(mark)); for(int i=1;i<=n;i++) { scanf("%d%d",&a[2*i-1],&a[2*i]); if(a[2*i-1]>a[2*i]) { swap(a[2*i-1],a[2*i]); mark[i]=1; } b[i][0]=a[2*i-1];b[i][1]=a[2*i]; } for(int i=1;i<=m;i++) { scanf("%d",&a[2*n+i]); c[i]=a[2*n+i]; } sort(a+1,a+2*n+m+1); for(int i=1;i<=n;i++) for(int j=0;j<=1;j++) b[i][j]=lower_bound(a+1,a+2*n+m+1,b[i][j])-a; for(int i=1;i<=m;i++) { c[i]=lower_bound(a+1,a+2*n+m+1,c[i])-a; d[c[i]]=i; } size=2*n+m; tree *xtr; (xtr=new tree)->build(1,size); for(int i=1;i<=n;i++) { last[i].t=xtr->qmax(b[i][0],b[i][1]-1); last[i].id=i; if(last[i].t!=0&&mark[i]==0) mark[i]=1; } sort(last+1,last+n+1,cmp); memset(d,0,sizeof(d)); xtr->build(1,size); int pnt=1; for(int i=m;i>=0;i--) { while(pnt<=n&&last[pnt].t==i) { int o=xtr->qsum(b[last[pnt].id][1],size); mark[last[pnt].id]^=(o&1); pnt++; } if(i!=0)xtr->add(c[i]); } long long ans=0; for(int i=1;i<=n;i++) ans+=a[b[i][mark[i]]]; cout<<ans; return 0; }
转载请注明原文地址: https://www.6miu.com/read-35159.html

最新回复(0)