283E&EZOJ #89 Cow Tennis Tournament

传送门

分析

我们考虑用所有的情况减去不合法的情况

不难想出所有情况为$C_n^3$

于是我们考虑不合法的情况

我们知道对于一个不合法的三元组$(a,b,c)$一定是修改后$a<b,b>c$

于是我们可以离散化后用线段树维护每个点被覆盖了几次

所以每次对于一个点$i$,比它大的点的个数即为在它前面修改次数为偶数的数量加在它后面修改次数为奇数的数量

而产生的不合法情况即为$C_{sum_i}^2$

我们再统计前后两种情况的时候将修改排序然后分别从后往前和从前往后各跑一次即可

每次只要区间不再覆盖点$i$则统计答案

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
struct node {
    long long le,ri;
};
node q[100100];
long long d[400100],col[400100],n,m;
long long a[100100],sum[100100];
vector<long long>id;
inline bool cmp1(const node x,const node y){
    return x.le==y.le?x.ri<y.ri:x.le<y.le;
}
inline bool cmp2(const node x,const node y){
    return x.ri==y.ri?x.le>y.le:x.ri>y.ri;
}
inline void update(long long le,long long ri,long long wh,long long x,long long y){
    if(x>y)return;
    if(le>=x&&ri<=y){
      col[wh]^=1;
      d[wh]=(ri-le+1)-d[wh];
      return;
    }
    long long mid=(le+ri)>>1;
    if(col[wh]){
      col[wh<<1]^=1;
      col[wh<<1|1]^=1;
      d[wh<<1]=(mid-le+1)-d[wh<<1];
      d[wh<<1|1]=(ri-mid)-d[wh<<1|1];
      col[wh]=0;
    }
    if(mid>=x)update(le,mid,wh<<1,x,y);
    if(mid<y)update(mid+1,ri,wh<<1|1,x,y);
    d[wh]=d[wh<<1]+d[wh<<1|1];
}
inline long long Q(long long le,long long ri,long long wh,long long x,long long y){
    if(x>y)return  0;
    if(le>=x&&ri<=y)return d[wh];
    long long mid=(le+ri)>>1,ans=0;
    if(col[wh]){
      col[wh<<1]^=1;
      col[wh<<1|1]^=1;
      d[wh<<1]=(mid-le+1)-d[wh<<1];
      d[wh<<1|1]=(ri-mid)-d[wh<<1|1];
      col[wh]=0;
    }
    if(mid>=x)ans+=Q(le,mid,wh<<1,x,y);
    if(mid<y)ans+=Q(mid+1,ri,wh<<1|1,x,y);
    d[wh]=d[wh<<1]+d[wh<<1|1];
    return ans;
}
int main(){
    long long i,j,k;
    scanf("%lld%lld",&n,&m);
    for(i=1;i<=n;i++)scanf("%lld",&a[i]),id.push_back(a[i]);;
    sort(id.begin(),id.end());
    id.erase(unique(id.begin(),id.end()),id.end());
    for(i=1;i<=m;i++)
      scanf("%lld%lld",&q[i].le,&q[i].ri);
    sort(q+1,q+m+1,cmp1);
    long long Ans=n*(n-1)*(n-2)/6;
    j=1;
    for(i=1;i<=m;i++){
      for(j;j<=lower_bound(id.begin(),id.end(),q[i].le)-id.begin();j++)
        sum[j]+=(n-j)-Q(1,n,1,j+1,n);
      update(1,n,1,lower_bound(id.begin(),id.end(),q[i].le)-id.begin()+1,
             upper_bound(id.begin(),id.end(),q[i].ri)-id.begin());
    }
    for(j;j<=n;j++)sum[j]+=(n-j)-Q(1,n,1,j+1,n);
    memset(d,0,sizeof(d));
    memset(col,0,sizeof(col));
    sort(q+1,q+m+1,cmp2);
    j=n;
    for(i=1;i<=m;i++){
      for(j;j>=upper_bound(id.begin(),id.end(),q[i].ri)-id.begin()+1;j--)
        sum[j]+=Q(1,n,1,1,j-1);
      update(1,n,1,lower_bound(id.begin(),id.end(),q[i].le)-id.begin()+1,
             upper_bound(id.begin(),id.end(),q[i].ri)-id.begin());
    }
    for(j;j>0;j--)sum[j]+=Q(1,n,1,1,j-1);
    for(i=1;i<=n;i++)Ans-=sum[i]*(sum[i]-1)/2;
    cout<<Ans;
    return 0;
}
posted @ 2018-11-04 21:35  水题收割者  阅读(318)  评论(0编辑  收藏  举报