「CF1284B」 New Year and Ascent Sequence

题意

\(n\) 个序列,在其中选择可以相同的两个首尾相连,可以得到 \(n^2\) 种方案。

问其中多少至少有一个顺序对。

分析

考虑用总数减去不合法的数量,即求不含有顺序对的数量。

这种序列就是单调不增序列,要求两个子序列也是单调不增,这在输入时就可以 \(O(len)\) 判断。

因为大序列单调不增,那么就要求前面小序列的最后一项大于等于后面小序列的第一项。

我们只需要根据一个小序列的最后一项来找比它还小的就可以了。

用值域线段树维护,把每个不增小序列的第一项放进去就可以了。

复杂度 \(O(n\log V)\)

Code

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
// static char buf[100],*p1=buf,*p2=buf,obuf[100],*p3=obuf;
// #define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,100,stdin),p1==p2)?EOF:*p1++
// #define putchar(x) (p3-obuf<100)?(*p3++=x):(fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=x)
mt19937_64 rnd(chrono::system_clock::now().time_since_epoch().count());
#define dbg(x) cout<<#x<<": "<<x<<"\n"
#define usetime() printf("time: %.3lfs\n",clock()*1.0/CLOCKS_PER_SEC)
inline ll read(){ll x=0,f=1;char c=getchar();while(c<48||c>57){if(c==45)f=0;c=getchar();}while(c>47&&c<58)x=(x<<3)+(x<<1)+(c^48),c=getchar();return f?x:-x;}
inline void write(ll x){if(!x){putchar(48);putchar('\n');return;}short top=0,s[40];if(x<0)x=-x,putchar(45);while(x)s[top++]=x%10^48,x/=10;while(top--)putchar(s[top]);putchar('\n');}
namespace tobe{
    const ll maxn=1e6+5,mod=998244353;
	ll n,lst[maxn],len[maxn];
	vector<ll>a;
	bool vis[maxn];
	struct node{
		ll l,r,val;
	}t[maxn<<2];
	#define ls (x<<1)
	#define rs (x<<1|1)
	#define mid ((t[x].l+t[x].r)>>1)
	inline void pushup(ll x){t[x].val=t[ls].val+t[rs].val;}
	inline void build(ll x,ll l,ll r){
		t[x].l=l,t[x].r=r;
		if(l==r)return;
		build(ls,l,mid),build(rs,mid+1,r);
	}
	inline void update(ll x,ll pos,ll k){
		if(t[x].l==t[x].r)return t[x].val+=k,void();
		if(pos<=mid)update(ls,pos,k);
		else update(rs,pos,k);
		pushup(x);
	}
	inline ll query(ll x,ll l,ll r){
		if(l<=t[x].l&&t[x].r<=r)return t[x].val;
		ll res=0;
		if(l<=mid)res+=query(ls,l,r);
		if(r>mid)res+=query(rs,l,r);
		return res;
	}
    inline void mian(){
		n=read();
		build(1,0,1e6);
		for(ll i=1;i<=n;++i){
			len[i]=read(),a.clear();
			for(ll j=1;j<=len[i];++j){
				a.push_back(read());
			}lst[i]=a.back();
			vis[i]=1;
			for(ll j=1;j<len[i];++j){
				if(a[j-1]<a[j])vis[i]=0;
			}
			if(!vis[i])continue;
			update(1,a[0],1);
		}
		ll ans=n*n;
		for(ll i=1;i<=n;++i){
			if(vis[i]){
				ans-=query(1,0,lst[i]);
			}
		}write(ans);
    }
}
signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ll t=1;
    while(t--)tobe::mian();
    // fwrite(obuf,p3-obuf,1,stdout);
    return 0;
}
posted @ 2025-03-05 20:37  run-away  阅读(18)  评论(0)    收藏  举报