题意
题解
因为每次添加的字符都不一样,即询问的区间在之前有多少个添加的区间覆盖了,就是最长的长度。
对于在询问前面的操作,计算
l
≤
n
o
w
l
,
r
≥
n
o
w
r
l\leq nowl,r\geq nowr
l≤nowl,r≥nowr的操作个数。
因为还要保证,在自己前面即
t
i
<
n
o
w
t
t_i<nowt
ti<nowt。
所以是个三维偏序问题,可以简单的用
C
D
Q
CDQ
CDQ解决。
比赛的时候不会写,哭了,好好学了一波。
还是比较板的,记录下更新操作,为了方便写,我们默认时间序为第一层排序,第二层分治对 r r r倒序排序,第三层是树状数组记录当前比自己右端点大的左端点的贡献。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f3f3f3f3f
typedef long long ll;
using namespace std;
const int N = 2e5+500;
const int maxn=2e5+500;
struct BIT{ //树状数组板子
int bit[N],n;
inline int lowbit(int x){
return x&(-x);
}
void Add(int x,int d){
while(x<=n){
bit[x]+=d;
x+=lowbit(x);
}
}
int Ask(int x){
int ans=0;
while(x){
ans+=bit[x];
x-=lowbit(x);
}
return ans;
}
}tr;
struct node{
int id,l,r,tp;
node(){}
node(int _id,int _l,int _r,int _tp):id(_id),l(_l),r(_r),tp(_tp){}
}q[maxn],tmp[maxn];
int ans[maxn];
void cdq(int l,int r){
if(l>=r)return ;
int mid=(l+r)>>1;
cdq(l,mid),cdq(mid+1,r);
int num=l-1,i,j;
for(i=l,j=mid+1;i<=mid&&j<=r;){
if(q[i].r>=q[j].r){
if(q[i].tp)tr.Add(q[i].l,1);
tmp[++num]=q[i++];
}
else{
if(!q[j].tp)ans[q[j].id]+=tr.Ask(q[j].l);
tmp[++num]=q[j++];
}
}
while(i<=mid){
if(q[i].tp)tr.Add(q[i].l,1);
tmp[++num]=q[i++];
}
while(j<=r){
if(!q[j].tp)ans[q[j].id]+=tr.Ask(q[j].l);
tmp[++num]=q[j++];
}
for(int k=l;k<=mid;k++)if(q[k].tp)tr.Add(q[k].l,-1);
for(int k=l;k<=r;k++)q[k]=tmp[k];
}
int main(){
int n,Q,cnt=0;cin>>n>>Q;
tr.n=n;
for(int i=1;i<=Q;i++){
int t,l,r;scanf("%d%d%d",&t,&l,&r);
if(t==1)q[i]=node(-1,l,r,1);
else{
q[i]=node(++cnt,l,r,0);
}
}
cdq(1,Q);
for(int i=1;i<=cnt;i++)printf("%d\n",ans[i]);
}