版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
LINK->牛客
链接:https://ac.nowcoder.com/acm/contest/1108/H
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
Special Judge, 64bit IO Format: %lld
题目描述
Bobo 精通数据结构!他想维护一个线段的集合 S。初始时,S 为空。他会依次进行 q 次操作,操作有 2 种。
- 类型 1:给出 l, r,向集合 S 中插入线段 [l, r].
- 类型 2:给出 l, r,询问满足 [x,y]∈S[x, y] \in S[x,y]∈S 且 x≤l≤r≤yx \leq l \leq r \leq yx≤l≤r≤y 的线段 [x, y] 数量。
帮 Bobo 求出每次询问的答案。
输入描述:
输入文件包含多组数据,请处理到文件结束。
每组数据的第一行包含 2 个整数 n 和 q. 其中 n 表示操作中 r 的最大值。
接下来 q 行中的第 i 行包含 3 个整数 ti,li,rit_i, l_i, r_iti,li,ri,表示第 i 个操作属于类型 tit_iti,对应的参数是 lil_ili 和 rir_iri.
输出描述:
对于每个类型 2 的询问,输出 1 个整数表示对应的数量。
示例1
输入
复制
1 2
1 1 1
2 1 1
4 4
1 1 4
2 2 3
1 1 4
2 2 3
输出
复制
1
1
2
备注:
- 1≤n,q≤1051 \leq n, q \leq 10^51≤n,q≤105
- ti∈{1,2}t_i \in {1, 2}ti∈{1,2}
- 1≤li≤ri≤n1 \leq l_i \leq r_i \leq n1≤li≤ri≤n
- 对于 ti=2t_i = 2ti=2 的操作,ri−li≤2r_i - l_i \leq 2ri−li≤2 成立。
- 数据组数不超过 10.
1A还是很开心的~~所以什么是树套树o(╥﹏╥)o
想法在后面啊
#include<bits/stdc++.h>
using namespace std;
const int N=500010;
int c[N],num[N],bz[N],n;
inline int lowbit(int x)//单点修改,区间查询 (差分思想
{
return x&(-x);
}
inline void modify(int pos,int x)
{
for(;pos<=n;pos+=lowbit(pos))
{
c[pos]+=x;
}
}
int query(int pos)
{
int res=0;
for(;pos;pos-=lowbit(pos))
{
res+=c[pos];
}return res;
}
int main()
{
int m;
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<=n;i++) c[i]=num[i]=bz[i]=0;
int op,x,y;
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&x,&y);
modify(x,1);
modify(y+1,-1);
if(x!=y) num[x]++;
else bz[x]++;
}else
{
scanf("%d%d",&x,&y);
int ans;
//cout<<query(x)<<" "<<query(y)<<endl;
if(x==y) ans=query(x);
else if(x==y-1)
{
ans=query(y)-bz[y]-num[y];
}
else
{
ans=query(y)-num[x+1]-num[y]-bz[y];
}
printf("%d\n",ans);
}
}
}
}
bz是作为重(chong)点的个数; num表示是这个点作为左端点的个数
- 设一线段的两个端点分别x ,y
- 树状数组在x端处理+1 ,y+1处理-1 那么对于x-y之间的线段的个数至少都为1 而对于后端点在y之后线段就是无效的(差分+前缀和)
- 对于x=y 就相当单点啦,就判断所以达到y的线段个数 那就是前缀和
- 对于y=x+1 那就是从达到y的线段个数中除去这个是重点以及左端点的个数
- 对于y=x+2 同样至少要是能达到y的线段 减去 y是重点或左端点的个数再减去中间的那个点作为左端点的个数 {所以现在能达到y的左端点至少是在x 开始的也就符合条件了}(这里不能减去中间点作为重点的个数因为重点根本就不在能达到y的线段里面啊)
- 更简洁
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int c[N],bz[N],num[N],n,m;
inline int lowbit(int x)
{
return x&(-x);
}
void add(int x,int v)
{
for(;x<=n;x+=lowbit(x)) c[x]+=v;
}
int sum(int x)
{
int ans=0;
for(;x;x-=lowbit(x)) ans+=c[x];
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<=n;i++) c[i]=bz[i]=num[i]=0;
while(m--)
{
int oo,a,b;scanf("%d%d%d",&oo,&a,&b);
if(oo==1)
{
add(a,1);add(b+1,-1);
if(a==b) bz[a]++;
else num[a]++;
}else
{
if(a==b) printf("%d\n",sum(a));
else if(a==b-1) printf("%d\n",sum(b)-num[b]-bz[b]);
else printf("%d\n",sum(b)-bz[b]-num[b]-num[a+1]);
}
}
}
}