stable_sort
保平安。
解析
dp方程显而易见,关键就是如何进行这个四维偏序的转移。
考虑三维偏序(比如拦截导弹)我们是如何做的?
先按照第一维排序,然后分治解决前一半,接下来把前一半的第一维看成0,第二维看成1,按照第二维排序后,用所有的0对1进行转移。
本题也延续这样的思想,先按照第一维排序,前一半看成0,后一半看成1,然后再对其进行一次三维偏序的转移,有所不同就是只有打上0标记的才可以加入树状数组,打上1标记的才可以接受转移。
换句话说,就是只能让0,0向1,1转移。
注意排序一定要排彻底!
stable_sort
是好东西,在常数可以接受的情况下大大降低写错的风险。
其实主要出错就是重点的时候,注意一下把cmp函数写好也不会有问题。
代码
(毕竟是模板,就贴的是不用 stable_sort
也能过的)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;
const int N=8e4+100;
const int C=205;
const int mod=998244353;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m;
#define pr pair<ll,ll>
#define mkp make_pair
pr f[N];
int q[N],cnt;
void operator += (pr &a,pr b){
if(a.first<b.first) a=b;
else if(a.first==b.first) (a.second+=b.second)%=mod;
}
inline void add(int p,pr o){
for(;p<=cnt;p+=p&-p) f[p]+=o;
return;
}
inline pr ask(int p){
pr res=mkp(0,1);
for(;p;p-=p&-p) res+=f[p];
return res;
}
inline void clear(int p){
for(;p<=cnt;p+=p&-p) f[p]=mkp(0,1);
}
struct node{
int x[5],v;
pr dp;
bool op;
}p[N];
inline void print(node o,bool op=1){
printf("[(%d %d %d %d) dp=(%lld %lld) v=%d op=%d] ",
o.x[1],o.x[2],o.x[3],o.x[4],o.dp.first,o.dp.second,o.v,o.op);
if(op) putchar('\n');
return;
}
bool cmp1 (const node &a,const node &b){
if(a.op!=b.op) return a.op>b.op;
if(a.x[1]!=b.x[1]) return a.x[1]<b.x[1];
else if(a.x[2]!=b.x[2]) return a.x[2]<b.x[2];
else if(a.x[3]!=b.x[3]) return a.x[3]<b.x[3];
else if(a.x[4]!=b.x[4]) return a.x[4]<b.x[4];
else return a.dp<b.dp;
}
bool cmp2 (const node &a,const node &b){
if(a.x[2]!=b.x[2]) return a.x[2]<b.x[2];
else if(a.x[3]!=b.x[3]) return a.x[3]<b.x[3];
else if(a.x[4]!=b.x[4]) return a.x[4]<b.x[4];
else if(a.x[1]!=b.x[1]) return a.x[1]<b.x[1];
else return a.op>b.op;
}
bool cmp3 (const node &a,const node &b){
if(a.x[3]!=b.x[3]) return a.x[3]<b.x[3];
else if(a.x[4]!=b.x[4]) return a.x[4]<b.x[4];
else if(a.x[1]!=b.x[1]) return a.x[1]<b.x[1];
else if(a.x[2]!=b.x[2]) return a.x[2]<b.x[2];
else return a.dp<b.dp;
}
void solve2(int l,int r){
if(l==r){
//p[l].dp+=mkp(p[l].v,1);
return;
}
int mid=(l+r)>>1;
solve2(l,mid);
sort(p+l,p+mid+1,cmp3);
sort(p+mid+1,p+r+1,cmp3);
int pl=l;
for(int i=mid+1;i<=r;i++){
while(pl<=mid&&p[pl].x[3]<=p[i].x[3]){
if(p[pl].op){
add(p[pl].x[4],p[pl].dp);
}
++pl;
}
if(!p[i].op){
pr o=ask(p[i].x[4]);
o.first+=p[i].v;
if(o.first!=p[i].v) p[i].dp+=o;
}
}
for(int i=l;i<pl;i++){
if(p[i].op) clear(p[i].x[4]);
}
//printf(" solve2: ");
//for(int i=l;i<=r;i++) print(p[i],i==r);
sort(p+mid+1,p+r+1,cmp2);
solve2(mid+1,r);
return;
}
void solve1(int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
solve1(l,mid);
//sort(p+l,p+mid+1,cmp2);
//sort(p+mid+1,p+r+1,cmp2);
for(int i=l;i<=mid;i++) p[i].op=1;
for(int i=mid+1;i<=r;i++) p[i].op=0;
sort(p+l,p+r+1,cmp2);
//printf("\nsolve1: ");
//for(int i=l;i<=r;i++) print(p[i],i==r);
solve2(l,r);
sort(p+l,p+r+1,cmp1);
solve1(mid+1,r);
return;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=4;j++) p[i].x[j]=read();
p[i].v=read();
q[++cnt]=p[i].x[4];
p[i].dp=mkp(p[i].v,1);
}
sort(q+1,q+1+cnt);
cnt=unique(q+1,q+1+cnt)-q-1;
for(int i=1;i<=n;i++){
p[i].x[4]=lower_bound(q+1,q+1+cnt,p[i].x[4])-q;
}
sort(p+1,p+1+n,cmp1);
solve1(1,n);
pr ans=mkp(0,1);
for(int i=1;i<=n;i++) ans+=p[i].dp;
printf("%lld\n%lld\n",ans.first,ans.second);
return 0;
}
/*
*/