传送门:牛客
题目描述:
首先给定一个定值k,支持如下操作(在数轴上)
1. 加入一条线段[l,r]
2. 删除一条已经存在的线段
3. 给定x,问有多少个区间包含x+kt,其中t是一个整数变量,即t ∈ Z
比如说当x=2,k=3的时候,区间[7,10]是应该算入答案的,因为x+2k=8,且7 ≤ 8 ≤ 10
如果n=0,那么你只需要输出一行"fafa"然后结束程序即可(注意不输出双引号)
输入:
10 7
1 3393 14151
3 13229
1 3427 18356
1 7602 20138
1 8566 28714
1 1076 32552
2 3427 18356
2 8566 28714
3 10962
1 387 7783
输出:
1
3
一道线段树+离散化+差分的题目,综合性和代码量都比较大,不愧是牛客上的5星题
首先我们看一下我们的题目,会发现k是给定的,并且应有两种情况需要考虑
先考虑 k = 0 k=0 k=0的情况,此时我们会发现我们的题目变成了问有多少个区间包含 x x x.对于这种问题我们首先肯定会有一种比较朴素的想法,就是每有一段线段,就将线段里的所有点加上上1.但是这种想法显然会超时,所以我们需要优化一下.此时就需要我们的差分思想了,我们可以将线段的开头加上1,结尾减少1,这样差分的思想就很好的解决了我们的问题.维护完线段之后再跑一个前缀和即可.但是我们此时的问题不是离线的,而是在线的.所以我们需要使用线段树代替朴素的数组来维护我们的差分.
但是,我们发现我们的 l , r l,r l,r非常大,达到了 1 e 9 1e9 1e9,此时我们的线段树显然无法维护这么大的数据.所以我们需要进行离散化操作.具体如何进行离散化可以观看后文代码
然后我们考虑 k k k不为0的情况,此时我们看一下我们的式子,会发现我们的 t t t只要是整数就可.这意味什么呢,意味着我们的 y y y等于 x % k + N ∗ k , N ≥ 0 x\%k+N*k,N\geq0 x%k+N∗k,N≥0,那么此时计算我们的所有区间里有多少值包括了 y y y.我们可以将这个问题进行一个简单的转化,也就是求所有区间的点对 k k k取模后有多少值和 x % k x\%k x%k相等.
当线段的长度大于等于 k k k时,显然我们的线段会包括 y y y,因为大于等于 K K K意味我们的余数肯定充满了K;当我们的线段长度小于 k k k,我们可以将线段的左右端点对 k k k取模,得到 L , R L,R L,R,如果此时我们的 L < = R L<=R L<=R(注意此时相等的情况肯定是原 l l l= r r r,因为如果不是这种情况,我们的线段的长度肯定大于等于 k k k了),那么我们直接 a d d ( L , 1 ) , a d d ( R + 1 , − 1 ) add(L,1),add(R+1,-1) add(L,1),add(R+1,−1)即可.当我们的 L > R L>R L>R时,我们需要 a d d ( L , 1 ) , a d d ( K + 1 , − 1 ) , a d d ( 1 , 1 ) , a d d ( R + 1 , − 1 ) add(L,1),add(K+1,-1),add(1,1),add(R+1,-1) add(L,1),add(K+1,−1),add(1,1),add(R+1,−1).
但是此时会存在一个问题,就是我们的数据的初始状态是0,但是我们取模也存在0这种贡献,所以会发生错误.此时我们可以选择将所有取模后的结果+1来避免产生0
下面是具体的代码部分:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int n,k;
struct Segment_tree{
int l,r,sum;
}tree[maxn*4];
void build(int l,int r,int rt) {
tree[rt].l=l;tree[rt].r=r;
if(l==r) {
tree[rt].sum=0;
return ;
}
int mid=(l+r)>>1;
build(lson);build(rson);
tree[rt].sum=tree[ls].sum+tree[rs].sum;
}
void update(int rt,int pos,int v) {
if(tree[rt].l==pos&&tree[rt].r==pos) {
tree[rt].sum+=v;
return ;
}
int mid=(tree[rt].l+tree[rt].r)>>1;
if(pos<=mid) update(ls,pos,v);
else update(rs,pos,v);
tree[rt].sum=tree[ls].sum+tree[rs].sum;
}
int query(int l,int r,int rt) {
if(tree[rt].l==l&&tree[rt].r==r) {
return tree[rt].sum;
}
int mid=(tree[rt].l+tree[rt].r)>>1;
if(r<=mid) return query(l,r,ls);
else if(l>mid) return query(l,r,rs);
else return query(l,mid,ls)+query(mid+1,r,rs);
}
vector<int>v;
struct O{
int opt,l,r;
}opt[maxn];
int getid(int x) {
//加一是为了将0位置变成1,也就是整体往后移一格
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
int main() {
n=read();k=read();
if(n==0) {
puts("fafa");
return 0;
}
for(int i=1;i<=n;i++) {
int Opt=read();
if(Opt==1) {
int l=read(),r=read();
opt[i]={Opt,l,r};
v.push_back(l);v.push_back(r);
}
else if(Opt==2) {
int l=read(),r=read();
opt[i]={Opt,l,r};
v.push_back(l);v.push_back(r);
}
else {
int x=read();
opt[i]={Opt,x,x};
v.push_back(x);
}
}
if(k==0) {
//进行离散化操作
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int Size=v.size();
//离散化结束
build(1,Size*2,1);//有点懒,懒得算具体数值了,直接取2倍了,下同
for(int i=1;i<=n;i++) {
if(opt[i].opt==1) {
int l=getid(opt[i].l),r=getid(opt[i].r);
update(1,l,1);update(1,r+1,-1);
}
else if(opt[i].opt==2) {
int l=getid(opt[i].l),r=getid(opt[i].r);
update(1,l,-1);update(1,r+1,1);
}
else {
int x=getid(opt[i].l);
printf("%d\n",query(1,x,1));
}
}
}
else {
build(1,k*2,1);
for(int i=1;i<=n;i++) {
if(opt[i].opt==1) {
if(opt[i].r-opt[i].l+1>=k) {
update(1,1,1);update(1,k+1,-1);
}
else {
//取模后加一
int l=opt[i].l%k+1,r=opt[i].r%k+1;
if(l<r) {
update(1,l,1);update(1,r+1,-1);
}
else {
update(1,l,1);update(1,k+1,-1);
update(1,1,1);update(1,r+1,-1);
}
}
}
else if(opt[i].opt==2) {
if(opt[i].r-opt[i].l+1>=k) {
update(1,1,-1);update(1,k+1,1);
}
else {
int l=opt[i].l%k+1,r=opt[i].r%k+1;
if(l<r) {
update(1,l,-1);update(1,r+1,1);
}
else {
update(1,l,-1);update(1,k+1,1);
update(1,1,-1);update(1,r+1,1);
}
}
}
else {
int x=opt[i].l%k+1;
printf("%d\n",query(1,x,1));
}
}
}
return 0;
}