t(t<=1e4)组样例,每次给定n(n<=2e5)个城市,
这n个城市在数轴上,用[1,n]表示,
m(m<=2e5)天,第i天让区间[li,ri](1<=li<=ri<=n)的城市都下雨,
你有k(k<=10)次机会,可以选出k天来,让这k天不下雨
求最大的m天都不下雨的城市数
Submission #230250470 - Codeforces SSRS代码(ST表优化dp)
转化一下题意,即等价于数轴上点[1,n],m条线段,你可以撤掉最多k条线段,
问没有被线段覆盖的点的个数最大是多少
C1的时候k=2,所以可以分被覆盖了0次/1次/2次讨论
而C2的时候k=10,不太能讨论,所以考虑类似地从左到右的扫描线
dp[i][j]表示当前考虑到点i,已经用了j次撤销机会,点i必不被线段覆盖时,[1,i]的答案最大是多少
转移可以枚举前一个必不被线段覆盖的点位于哪里,
假设位于点x,然后就只需要考虑左端点位于[x+1,i]之间,且右端点在点i及右侧的线段,
假设这中间的线段有k2条,dp[i][j]就可以从dp[x][j-k2]转移而来,用了k2次机会,使得i不被覆盖
由于k<=10,所以只需考虑保留能覆盖点i,且左端点最靠右的10条线段
暴力做复杂度是,考虑数据结构优化,
假设两个能覆盖i的相邻线段,左端点分别为L1,L2(L1<=L2)
那么[L1,L2)之间的x是可以放在一起考虑的,
因为用到的撤销机会是相同的,用线段树维护区间最大值即可
得到i的结果后,单点更新i的值即可,复杂度
参考SSRS的代码后,发现这个log也是可以省掉的,
将其改为ST表的区间查询和单点更新即可,复杂度
// Problem: C2. Doremy's Drying Plan (Hard Version)
// Contest: Codeforces - Codeforces Round 906 (Div. 1)
// URL: https://codeforces.com/contest/1889/problem/C2
// Memory Limit: 1024 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<
using namespace std;
const int N=2e5+10,K=11,INF=0x3f3f3f3f;
struct segtree{
int n;
struct node{int l,r,v;}e[N<<2];
#define l(p) e[p].l
#define r(p) e[p].r
#define v(p) e[p].v
void up(int p){v(p)=max(v(p<<1),v(p<<1|1));}
void bld(int p,int l,int r){
l(p)=l;r(p)=r;v(p)=-INF;
if(l==r){return;}
int mid=l+r>>1;
bld(p<<1,l,mid);bld(p<<1|1,mid+1,r);
up(p);
}
void init(int _n){n=_n;bld(1,0,n);}
void chg(int p,int x,int v){
if(l(p)==r(p)){v(p)=max(v(p),v);return;}
int mid=l(p)+r(p)>>1;
chg(p<<1|(x>mid),x,v);
up(p);
}
int amx(int p,int ql,int qr){
if(ql>qr)return -INF;
if(ql<=l(p)&&r(p)<=qr)return v(p);
int mid=l(p)+r(p)>>1,res=-INF;
if(ql<=mid)res=max(res,amx(p<<1,ql,qr));
if(qr>mid)res=max(res,amx(p<<1|1,ql,qr));
return res;
}
}seg[K];
multisetq;
int t,n,m,k,l[N],r[N],tmp[N];
vectoradd[N],del[N];
int sol(){
sci(n),sci(m),sci(k);
q.clear();
rep(i,0,k){
seg[i].init(n);
seg[i].chg(1,0,0);
}
rep(i,1,m){
sci(l[i]),sci(r[i]);
add[l[i]].pb(i);
del[r[i]].pb(i);
}
q.insert(0);
rep(i,1,n){
for(auto &v:add[i]){
q.insert(i);
}
auto it=prev(q.end());
rep(j,0,k)tmp[j]=-INF;
for(int k2=0;k2<=k;it=prev(it),k2++){
int p=*it;
rep(j,0,k-k2){
int v=seg[j].amx(1,p,i);
tmp[j+k2]=max(tmp[j+k2],v+1);
}
if(p==0)break;
}
rep(j,0,k)seg[j].chg(1,i,tmp[j]);
for(auto &v:del[i]){
q.erase(q.find(l[v]));
}
add[i].clear();
del[i].clear();
}
int ans=0;
rep(i,0,k){
ans=max(ans,seg[i].amx(1,1,n));
}
return ans;
}
int main(){
sci(t); // t=1
while(t--){
pte(sol());
}
return 0;
}