题意:
有 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;
}