题意:
有
n
n
n个数,
m
m
m个限制,第
i
i
i个限制要求在
[
L
i
,
R
i
]
[L_i,R_i]
[Li,Ri]的最小值为
V
i
V_i
Vi,你要得到最小的逆序对数。
数据满足
n
,
m
<
=
1
0
6
n,m<=10^6
n,m<=106。
思路:
最近感觉自己的实力厚度有点不够,所以打算多做一点oi题目,来提高实力厚度。
这道题很容易想到把限制按照V从小到大排序,然后不断给整个区间修改为
V
i
V_i
Vi,现在设修改完以后每个点的值为
b
i
b_i
bi。
操作完就可以知道某个点会对哪一个V的限制起作用。
我们把每个点按照 b i b_i bi分类,然后考虑保留哪些 b i b_i bi,修改哪些 b i b_i bi。考虑最小的 b b b,可以发现我们肯定要选择最少点不改变,而且都要尽量靠前,这样对后面的影响最小。然后考虑从小到达枚举 b b b,因为大的会覆盖小的,大的 b b b如果被小的 b b b分开,那么大的一定是相互独立的,所以我们可以决定出要选哪一些位置。
然后就是考虑要怎么填数才能使得逆序对数 最少。然后我就想了一个不太严谨的贪心:小的b一定比大的b能够变化的空间更多,因此我们一定是先处理大的b,在用小的b去将就大的b。所以我们就先填大的,再填小的。然后我们可以发现,空的格子里面填的最优的数一定是从小到大的,否则交换能得到更优的结果。而且,加入我给某个格子填了i,那么这个最优的值一定是把左边连续的若干个变成i,而不会改变更大的最优的数的格子。
我们用一个栈来维护这个最优的数,然后用一个线段树来维护应该改变左边的哪一部分。这个线段树维护当前最优解和改成bi之后逆序对数的差值,只需要在确定某个点的之以后把左边增加1,右边减少1即可(类似)。
感觉这个题目的思路特别的绕。
#include<bits/stdc++.h>
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define dwn(i,x,y) for(int i=x;i>=y;i--)
#define ll long long
using namespace std;
template<typename T>inline void qr(T &x){
x=0;int f=0;char s=getchar();
while(!isdigit(s))f|=s=='-',s=getchar();
while(isdigit(s))x=x*10+s-48,s=getchar();
x=f?-x:x;
}
int cc=0,buf[31];
template<typename T>inline void qw(T x){
if(x<0)putchar('-'),x=-x;
do{buf[++cc]=int(x%10);x/=10;}while(x);
while(cc)putchar(buf[cc--]+'0');
}
const int N=1e6+10;
struct SGT{
int l,r,c,lazy;bool clr;
}t[N<<2];
#define lc p<<1
#define rc p<<1|1
#define mid (t[p].l+t[p].r)/2
void update(int p){
t[p].c=max(t[lc].c,t[rc].c);
}
void pushdown(int p){
if(t[p].clr){
t[lc].c=t[lc].lazy=0;
t[lc].clr=1;
t[rc].c=t[rc].lazy=0;
t[rc].clr=1;
t[p].clr=0;
}
if(t[p].lazy){
t[lc].c+=t[p].lazy;
t[lc].lazy+=t[p].lazy;
t[rc].c+=t[p].lazy;
t[rc].lazy+=t[p].lazy;
t[p].lazy=0;
}
}
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
t[p].c=0;
t[p].lazy=0;
t[p].clr=0;
if(l<r){
build(lc,l,mid);
build(rc,mid+1,r);
}
}
void change(int p,int x,int y,int k){
if(x<=t[p].l&&t[p].r<=y){
t[p].c+=k;
t[p].lazy+=k;
return;
}
pushdown(p);
if(x<=mid)change(lc,x,y,k);
if(mid<y)change(rc,x,y,k);
update(p);
}
void change2(int p,int x,int y){
if(x<=t[p].l&&t[p].r<=y){
t[p].c=t[p].lazy=0;
t[p].clr=1;
return;
}
pushdown(p);
if(x<=mid)change2(lc,x,y);
if(mid<y)change2(rc,x,y);
update(p);
}
int query(int p){
if(t[p].l==t[p].r){
if(t[p].c>=0)return 0;
return t[p].l;
}
pushdown(p);
if(t[lc].c<0)return max(t[lc].r,query(rc));
else return query(lc);
}
int n,m;
int cnt,s[N];
struct node{
int x,y,z;
node(int xx=0,int yy=0,int zz=0):x(xx),y(yy),z(zz){}
}a[N],sta[N];int tp;
vector<int>zuo[N],you[N];
int b[N];//the max num cover i
vector<int>pos[N],seg[N];//pos was valued i; segment have value i
bool used[N];
int ans[N];
int c[N];
bool cmp1(int p1,int p2){
return p1<p2;
}
bool cmp2(int p1,int p2){
if(a[p1].x!=a[p2].x)return a[p1].x<a[p2].x;
return a[p1].y>a[p2].y;
}
void add(int x){
for(;x<=n;x+=x&-x)c[x]++;
}
int calc(int x){
int ret=0;
for(;x;x-=x&-x)ret+=c[x];
return ret;
}
int testcase;
void solve(){
qr(n),qr(m);
rep(i,1,n){
zuo[i].clear();
you[i].clear();
}
cnt=0;
rep(i,1,m){
qr(a[i].x),qr(a[i].y),qr(a[i].z);
s[++cnt]=a[i].z;
}
sort(s+1,s+cnt+1);
cnt=unique(s+1,s+cnt+1)-s-1;
rep(i,1,m){
a[i].z=lower_bound(s+1,s+cnt+1,a[i].z)-s;
zuo[a[i].x].push_back(i);
you[a[i].y].push_back(i);
}
multiset<int>cover;
rep(i,1,cnt){
pos[i].clear();
seg[i].clear();
}
rep(i,1,m)seg[a[i].z].push_back(i);
rep(i,1,n){
for(int id:zuo[i])cover.insert(a[id].z);
b[i]=0;
if(cover.size()){
b[i]=*(--cover.end());
pos[b[i]].push_back(i);
}
for(int id:you[i])cover.erase(cover.find(a[id].z));
}
rep(i,1,n)used[i]=0;
bool flag=1;
rep(i,1,cnt){
sort(pos[i].begin(),pos[i].end(),cmp1);
sort(seg[i].begin(),seg[i].end(),cmp2);
int now=(int)pos[i].size()-1,last=n+1;
for(int j=(int)seg[i].size()-1;j>=0;j--){
node t=a[seg[i][j]];
if(last<=t.y)continue;
while(now>0&&pos[i][now-1]>=t.x)now--;
if(now<0||pos[i][now]>t.y||pos[i][now]<t.x){
flag=0;break;
}
last=pos[i][now];
used[last]=1;
}
if(!flag)break;
}
if(!flag){
puts("-1");
return;
}
build(1,1,n);
sta[tp=1]=node(1,n,cnt+1);
dwn(i,cnt,1){
for(int x:pos[i]){
if(used[x]){
ans[x]=i;
if(x>1)change(1,1,x-1,-1);
}
}
int len=query(1);
if(len){
while(tp&&sta[tp].y<=len)tp--;
if(tp){
sta[tp].x=len+1;
}
sta[++tp]=node(1,len,i);
change2(1,1,len);
}
for(int x:pos[i]){
if(!used[x]){
int l=1,r=tp,Mid,pos;
while(l<=r){
Mid=(l+r)/2;
if(sta[Mid].x<=x)pos=Mid,r=Mid-1;
else l=Mid+1;
}
ans[x]=sta[pos].z;
if(x<n)change(1,x+1,n,1);
}
}
for(int x:pos[i]){
if(used[x]){
if(x<n)change(1,x+1,n,1);
}
}
}
rep(x,1,n)if(!b[x]){
int l=1,r=tp,Mid,pos;
while(l<=r){
Mid=(l+r)/2;
if(sta[Mid].x<=x)pos=Mid,r=Mid-1;
else l=Mid+1;
}
ans[x]=sta[pos].z;
}
rep(i,1,n)c[i]=0;
ll tot=0;
dwn(i,n,1){
tot+=calc(ans[i]-1);
add(ans[i]);
}
qw(tot);puts("");
}
int main(){
// freopen("bubble6.in","r",stdin);
// freopen("bubble6.out","w",stdout);
int tt;qr(tt);
while(tt--)solve();
return 0;
}