10.29 cf283E合法三元環+線段樹
阿新 • • 發佈:2018-11-02
題意
思路
- pre_work sort+離散化
- 如何求合法三元組,考慮補集轉化,用C(n,3)-不合法的;
- 考慮不合法如何求,這個三元組必定有一個可以戰勝其他兩個,那麼只要統計出他能打敗的人,再C(cnt,2),再sum一下
- 如何統計他能打敗的人(in[i])
- 首先,我們考慮一個暴力,O(nnm);考慮一個矩陣,a[i][j]表示i和j對戰的結果,0表示i輸,1表示i贏,那麼可以只考慮右上方的rt三角形,每次修改只要baoli修改一個RT三角形即可
- 瓶頸在於區間修改及查詢,可以想到線段樹,又發現對於i來說只有覆蓋i的修改才對i有用,所以對於所有操作只要掃兩遍即可
- O(n+mlogn)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; ll read() { char ch=' '; ll f=1;ll x=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0';ch=getchar(); } return x*f; } const ll N=1e5+100; ll z[N]; struct node { ll l,r; }c[N]; bool cmp1(node a,node b) { return a.l<b.l; } bool cmp2(node a,node b) { return a.r>b.r; } struct tree { ll cnt0; ll cnt1; ll tag; }t[N<<2]; ll in[N]; void update(ll rt) { t[rt].cnt0=t[rt<<1].cnt0+t[rt<<1|1].cnt0; t[rt].cnt1=t[rt<<1].cnt1+t[rt<<1|1].cnt1; return ; } void build(ll rt,ll l,ll r) { t[rt].cnt0=1; t[rt].cnt1=0; t[rt].tag=0; if(l==r) { return ; } ll mid=(l+r) >> 1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); update(rt); } void pushdown(ll rt) { t[rt].tag=0; t[rt<<1].tag^=1; t[rt<<1|1].tag^=1; swap(t[rt<<1].cnt0,t[rt<<1].cnt1); swap(t[rt<<1|1].cnt0,t[rt<<1|1].cnt1); } void modify(ll rt,ll l,ll r,ll x,ll y) { if(l>=x&&r<=y) { swap(t[rt].cnt0,t[rt].cnt1); t[rt].tag^=1; return ; } if(t[rt].tag) pushdown(rt); ll mid=(l+r) >> 1; if(x<=mid) { modify(rt<<1,l,mid,x,y); } if(y>mid) { modify(rt<<1|1,mid+1,r,x,y); } update(rt); } ll query(ll rt,ll l,ll r,ll x,ll y) { if(l>=x&&r<=y) { return t[rt].cnt1; } if(t[rt].tag==1) { pushdown(rt); } ll mid=(l+r) >> 1; ll ret=0; if(x<=mid) { ret+=query(rt<<1,l,mid,x,y); } if(y>mid) { ret+=query(rt<<1|1,mid+1,r,x,y); } return ret; } int main() { ll n,m; n=read();m=read(); ll i,j; for(i=1;i<=n;i++) { z[i]=read(); } sort(z+1,z+1+n); for(i=1;i<=m;i++) { c[i].l=read(); c[i].r=read(); c[i].l=lower_bound(z+1,z+1+n,c[i].l)-z; c[i].r=upper_bound(z+1,z+1+n,c[i].r)-z-1; //cout<<c[i].l<<' '<<c[i].r<<endl; } sort(c+1,c+1+m,cmp1); build(1,1,n); for(i=1,j=1;i<n;i++) { while(c[j].l>=c[j].r&&j<=m) j++; while(c[j].l<=i&&j<=m) { modify(1,1,n,c[j].l,c[j].r); j++; while(c[j].l>=c[j].r&&j<=m) j++; } in[i]=query(1,1,n,i+1,n); } build(1,1,n); sort(c+1,c+1+m,cmp2); for(i=n,j=1;i>1;i--) { while(c[j].l>=c[j].r&&j<=m) j++; while(c[j].r>=i&&j<=m) { modify(1,1,n,c[j].l,c[j].r); j++; while(c[j].l>=c[j].r&&j<=m) j++; } in[i]+=i-1-query(1,1,n,1,i-1); } ll ans=n*(n-1)*(n-2)/6; for(i=1;i<=n;i++) { ans-=in[i]*(in[i]-1)/2; } cout<<ans<<endl; return 0; }