这一题先将区间转化成左闭又开的形式[L,R),然后将所有的区间左右端点按照从小大大排序。从左往右扫一遍,遇到区间左端点+1,区间右端点-1,就得到每个点被区间覆盖的次数。如果一个点是多个区间的端点,只有最右侧的覆盖次数才是最终的结果。例如区间[1,3)、[1,4)中,1就被覆盖了两次。所以在sorted array中,右侧的1的覆盖次数才是正确的。
之后可以通过map记录覆盖次数=1的端点贡献的区间内点的个数。eg., [a1,a2,a3]中,如果a1的覆盖次数为1,那么a1的贡献就是a2-a1。
之后从右向左扫描,记录后缀和(覆盖次数=1的点的个数)。因为相同的点只有最右侧的值才是正确的,所以第一次 扫描到某个点才计算其后缀和。
之后对于任意一个区间,就可以通过后缀和在O(1*log n)内(map获取元素值是log n,后缀和相减是O(1))求出该区间内覆盖次数=1的点的个数了。
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
using namespace std;
//2017 RoundB Problem C. Watson and Intervals
const int maxn=500010;
int T;
int N;
int M;
int L;
int R;
int A;
int B;
int C1;
int C2;
class node
{
public:
int val;
int pointidx;
bool start;
int cover;
public:
node()
{
val=0;
pointidx=0;
start=false;
cover=0;
}
node(int v,int p,bool s)
{
val=v;
pointidx=p;
start=s;
cover=0;
}
};
bool cmp(node a,node b)
{
return a.val<b.val;
}
pair<int,int>P[maxn];
node Point[maxn*2];
map<int,int>mplen;//point i to point i-1 for mplen[i]
map<int,int>mppresum;//suffix sum
int totalcover;
int main()
{
//freopen("input.txt","r",stdin);
freopen("C-large-practice.in","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
int cnt=0;
scanf("%d %d %d %d %d %d %d %d",&N,&L,&R,&A,&B,&C1,&C2,&M);
// if(ca!=15)
// {
// continue;
// printf("%d %d %d %d %d %d %d %d\n",N,L,R,A,B,C1,C2,M);
// return 0;
// }
// continue;
memset(P,0,sizeof(P));
memset(Point,0,sizeof(Point));
mplen.clear();
mppresum.clear();
totalcover=0;
P[0]=make_pair(L,R);
Point[cnt++]=node(L,0,true);
Point[cnt++]=node(R+1,0,false);
for(int i=1;i<N;i++)
{
int x=((long long)P[i-1].first*A+(long long)P[i-1].second*B+C1)%M;
int y=((long long)P[i-1].second*A+(long long)P[i-1].first*B+C2)%M;
int l=min(x,y);
int r=max(x,y);
P[i]=make_pair(x,y);//what if two start points are the same?
Point[cnt++]=node(l,i,true);//cover the points in [l,r)
Point[cnt++]=node(r+1,i,false);//remove nodes with same [l,r]
}
sort(Point,Point+cnt,cmp);
// for(int i=0;i<cnt;i++)
// {
// cout<<Point[i].val<<endl;//" "<<Point[i].pointidx<<" "<<Point[i].start<<endl;
// }
// cout<<"==="<<endl;
Point[0].cover=1;
for(int i=1;i<cnt;i++)
{
if(Point[i].start==true)
{
Point[i].cover=Point[i-1].cover+1;
}
else
{
Point[i].cover=Point[i-1].cover-1;
}
}
// for(int i=0;i<cnt;i++)
// {
// cout<<Point[i].val<<" "<<Point[i].pointidx<<" "<<(Point[i].start?"T":"F")<<" "<<Point[i].cover<<" ED"<<endl;
// }
for(int i=0;i<cnt;i++)
{
if(Point[i].cover>0)
{
totalcover+=Point[i+1].val-Point[i].val;//include [i,i+1]
}
}
//cout<<totalcover<<endl;
for(int i=0;i<cnt;i++)
{
if(Point[i].cover==1)//&&Point[i].start==true
{
mplen[Point[i].val]=Point[i+1].val-Point[i].val;
// cout<<Point[i].val<<" "<<mplen[Point[i].val]<<endl;
}
}
mppresum[Point[cnt-1].val]=mplen[Point[cnt-1].val];
for(int i=cnt-2;i>=0;i--)
{
if(mppresum.find(Point[i].val)==mppresum.end())
{
mppresum[Point[i].val]=mppresum[Point[i+1].val]+mplen[Point[i].val];
//cout<<Point[i].val<<" "<<mppresum[Point[i].val]<<" "<<mppresum[Point[i+1].val]<<" "<<mplen[Point[i].val]<<endl;
}
}
int maxlen=0;
for(int i=0;i<N;i++)
{
int l=min(P[i].first,P[i].second);
int r=max(P[i].first,P[i].second)+1;
// WA is caused due to add 1 first then take max
// int l=min(P[i].first,P[i].second+1);
// int r=max(P[i].first,P[i].second+1);
int tmp=mppresum[l]-mppresum[r];
// if(i==677) cout<<l<<" p "<<r<<endl;
// cout<<l<<" "<<r<<" "<<tmp<<endl;
maxlen=max(maxlen,tmp);
}
printf("Case #%d: %d\n",ca,totalcover-maxlen);
}
return 0;
}