題意
uoj768
構造長為 \(n\) 的序列 \(a\),滿足 \(m\) 條限制:\(\min_{j=L_i}^{R_i}\{a_j\}=V_i\),要求逆序對數最少
題解
21pts 暴力
先進行一些觀察:
- 逆序對只關心相對大小,所以 \(\forall a_j\) 必然 \(\in\{V_i\}\),可以完全離散化
- 經典結論:若 \(i<j,a_i>a_j\) 且交換後合法,則交換後更優
A
\(V_i=1\) 的限制等價於區間覆蓋 \(1\);\(V_i=0\) 的限制等價於區間中存在 \(0\)
類似一個普及貪心題:按 \(L\) 從大到小考慮,區間中有 \(0\) 就跳過,沒有就令第一個空位為 \(0\)(若第一個空位為 \(1\),則一定可以與區間中的 \(0\) 交換)
此時所有限制都滿足了,剩下的位置可以隨意填 \(0,1\),一定是字首 \(0\) 字尾 \(1\),列舉分界點即可
B
相當於一些位置給定,其餘位置隨意
根據觀察 2,空位是有序的,內部沒有逆序對
一個自然的想法是單獨考慮每個空位,令其與給定位置的逆序對數最少。事實上這樣就能滿足空位有序(反證,若有空位 \(i<j,a_i>a_j\),則“將 \(a_i\) 變成 \(a_j\)”和“將 \(a_j\) 變成 \(a_i\)”的增量互為相反數,一定有一個 \(\le0\))
也可以用決策單調性證明:
從前到後依次考慮每個空位,設 \(f[x]\) 表示當前位置填 \(x\) 與已經確定位置構成的逆序對數
空位會填 \(a_j=\text{argmin}\{f[x]\}\),令 \(f[1\sim a_j-1]+1\)
給定位置會令 \(f[1\sim a_j-1]+1,f[a_j+1\sim m]-1\),\(\text{argmin}\) 是單增的(若有 \(x<y,f[x]\ge f[y]\) 則修改後仍滿足)
C
相當於限制是獨立的
根據觀察 2,每個限制一定是在 \(L_i\) 處填 \(V_i\)。問題轉化為一些位置給定,其餘位置滿足 \(a_j\ge b_j\)
根據 B 猜測 \(a_j=\text{argmin}_{x\ge b_j}\{f[x]\}\)
證明類似。首先不論填什麼都會使 \(f[1\sim b_j-1]+1\),其次現在 \(b_j\sim a_j-1\) 劣於 \(a_j\),之後一定不會變優,所以給 \(f[b_j\sim a_j-1]+1\) 沒有影響
std
與 C 相比限制有重疊
\(V_i\) 大的可以替代掉小的。按 \(V_i\) 從大到小排序,同一 \(V_i\) 做 A,即可轉化成 C
時間複雜度 \(O(n\log n)\),空間複雜度 \(O(n)\)
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std; using namespace __gnu_pbds; using namespace __gnu_cxx;
#define For(i,x,y,...) for(int i=x,##__VA_ARGS__;i<=(y);++i)
#define rFor(i,x,y,...) for(int i=x,##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=x,##__VA_ARGS__;i<(y);++i)
#define pb emplace_back
#define sz(a) int((a).size())
#define all(a) (a).begin(),(a).end()
#define fi first
#define se second
#define mkp make_pair
typedef long long LL; typedef vector<int> Vi; typedef pair<int,int> Pii;
auto ckmax=[](auto &x,auto y) { return x<y ? x=y,true : false; };
auto ckmin=[](auto &x,auto y) { return y<x ? x=y,true : false; };
sfmt19937 mt(chrono::steady_clock::now().time_since_epoch().count());
int rnd(int l,int r) { return uniform_int_distribution<>(l,r)(mt); }
#define getchar() getchar_unlocked()
struct IO {
template<typename T>IO& operator >> (T &x) {
x=0;bool f=0;char c;while(!isdigit(c=getchar()))f|=c=='-';
do x=x*10+c-48;while(isdigit(c=getchar()));if(f)x=-x;
return *this;
}
} io;
#define cin io
template<typename T=int>T read() { T x; cin>>x; return x; }
const int mod = 998244353;
struct mint {
int x; mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
mint(LL y) { y%=mod, x=y<0?y+mod:y; }
mint& operator += (const mint &y) { x=x+y.x<mod?x+y.x:x+y.x-mod; return *this; }
mint& operator -= (const mint &y) { x=x<y.x?x-y.x+mod:x-y.x; return *this; }
mint& operator *= (const mint &y) { x=1ll*x*y.x%mod; return *this; }
friend mint operator + (mint x,const mint &y) { return x+=y; }
friend mint operator - (mint x,const mint &y) { return x-=y; }
friend mint operator * (mint x,const mint &y) { return x*=y; }
}; mint Pow(mint x,LL y=mod-2) { mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z; }
const int N = 1e6+5;
int n,m,o[N],L[N],R[N],V[N],a[N],b[N];
vector<Pii> q[N];
int fa[N];
int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]); }
#define ls (u<<1)
#define rs (u<<1|1)
#define mid (l+r>>1)
struct { int add; Pii mn; } t[N*4];
Pii operator + (const Pii &x,const Pii &y) { return x.fi<=y.fi ? x : y; }
void bld(int u=1,int l=1,int r=o[0]) {
t[u] = {0,{0,l}};
if( l == r ) return;
bld(ls,l,mid), bld(rs,mid+1,r);
}
void add(int ql,int qr,int x,int u=1,int l=1,int r=o[0]) {
if( qr < l || r < ql ) return;
if( ql <= l && r <= qr ) { t[u].add += x, t[u].mn.fi += x; return; }
add(ql,qr,x,ls,l,mid), add(ql,qr,x,rs,mid+1,r);
t[u].mn = t[ls].mn + t[rs].mn, t[u].mn.fi += t[u].add;
}
Pii argmin(int ql,int u=1,int l=1,int r=o[0]) {
if( r < ql ) return {1e9,0};
if( ql <= l ) return t[u].mn;
Pii res = argmin(ql,ls,l,mid) + argmin(ql,rs,mid+1,r);
return res.fi += t[u].add, res;
}
struct {
int t[N];
void clr() { memset(t+1,0,sizeof(int)*o[0]); }
void add(int i) { for(;i;i-=i&-i)++t[i]; }
int sum(int i) { int res=0; for(;i<=o[0];i+=i&-i)res+=t[i]; return res; }
} ft;
void MAIN() {
cin>>n>>m; For(i,1,m) cin>>L[i]>>R[i]>>V[i], o[++o[0]] = V[i];
sort(o+1,o+o[0]+1), o[0] = unique(o+1,o+o[0]+1)-o-1;
For(i,1,m) q[lower_bound(o+1,o+o[0]+1,V[i])-o].pb(L[i],R[i]);
iota(fa+1,fa+n+2,1);
rFor(i,o[0],1) {
sort(all(q[i]),greater<>());
int lst = n+1;
for(auto [l,r] : q[i]) if( r < lst ) {
int p = find(l);
if( p > r ) { cout<<"-1\n"; return; }
a[p] = i, lst = p;
}
for(auto [l,r] : q[i])
for(int p = find(l); p <= r; p = find(p)) b[p] = i, fa[p] = p+1;
}
// cerr<<"a: "; For(i,1,n) cerr<<a[i]<<" "; cerr<<'\n';
// cerr<<"b: "; For(i,1,n) cerr<<b[i]<<" "; cerr<<'\n';
bld();
For(i,1,n) if( a[i] ) add(a[i]+1,o[0],1);
For(i,1,n) {
if( a[i] ) add(a[i]+1,o[0],-1);
else a[i] = argmin(b[i]).se;
add(1,a[i]-1,1);
}
// cerr<<"a: "; For(i,1,n) cerr<<a[i]<<" "; cerr<<'\n';
LL ans = 0;
For(i,1,n) ans += ft.sum(a[i]+1), ft.add(a[i]);
cout<<ans<<'\n';
} signed main() {
#ifdef FT
freopen("in","r",stdin); freopen("out","w",stdout);
#endif
ios::sync_with_stdio(0);
int lft=read(); while( lft-- ) {
MAIN();
ft.clr();
For(i,1,o[0]) q[i].clear();
memset(a+1,0,sizeof(int)*n), memset(b+1,0,sizeof(int)*n);
o[0] = 0;
}
return 0;
}