P1972
题意:
给 一 个 数 组 a i , q 个 询 问 , 每 次 询 问 一 个 区 间 有 多 少 个 不 同 的 数 给一个数组a_i,q个询问,每次询问一个区间有多少个不同的数 给一个数组ai,q个询问,每次询问一个区间有多少个不同的数
思路:
搞
一
个
数
组
b
i
表
示
元
素
i
上
次
出
现
的
位
置
,
元
素
i
第
一
次
出
现
标
记
为
0
搞一个数组b_i表示元素i上次出现的位置,元素i第一次出现标记为0
搞一个数组bi表示元素i上次出现的位置,元素i第一次出现标记为0
例
如
:
对
于
a
i
:
1
例如:对于a_i:1
例如:对于ai:1
2
2
2
3
3
3
1
1
1
1
1
1
2
2
2
3
3
3
1
1
1
2
2
2
3
3
3
4
4
4
b
i
:
0
b_i: 0
bi:0
0
0
0
0
0
0
1
1
1
4
4
4
2
2
2
3
3
3
5
5
5
6
6
6
7
7
7
0
0
0
然
后
为
了
方
便
去
掉
了
0
,
就
把
全
部
加
一
即
:
然后为了方便去掉了0,就把全部加一即:
然后为了方便去掉了0,就把全部加一即:
b
i
:
1
b_i: 1
bi:1
1
1
1
1
1
1
2
2
2
5
5
5
3
3
3
4
4
4
6
6
6
7
7
7
8
8
8
1
1
1
然
后
对
于
每
个
询
问
就
是
询
问
i
∈
[
L
,
R
]
,
b
[
i
]
<
L
的
个
数
然后对于每个询问就是询问i∈[L,R],b[i] < L的个数
然后对于每个询问就是询问i∈[L,R],b[i]<L的个数
在
线
对
于
这
个
做
法
似
乎
有
点
不
方
便
,
所
有
用
了
离
线
。
在线对于这个做法似乎有点不方便,所有用了离线。
在线对于这个做法似乎有点不方便,所有用了离线。
然
后
先
按
L
升
序
排
算
一
次
,
再
按
R
升
序
算
一
次
;
然后先按L升序排算一次,再按R升序算一次;
然后先按L升序排算一次,再按R升序算一次;
我
这
方
法
好
像
很
蠢
,
貌
似
有
更
好
的
方
法
的
我这方法好像很蠢,貌似有更好的方法的
我这方法好像很蠢,貌似有更好的方法的
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int N = 1e6+10;
int n,q,a[N],b[N];
int pos[N];//表示i最新出现的位置
int read(){
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
int tree[N];
int lowbit(int x){
return x&(-x);
}
void update(int x,int dx){
while(x <= n){
tree[x] += dx;
x += lowbit(x);
}
}
int query(int x){
int res = 0;
while(x){
res += tree[x];
x -= lowbit(x);
}
return res;
}
struct Node{
int l,r,id;
}Q[N];
bool cmp1(Node a,Node b){
return a.l < b.l;
}
bool cmp2(Node a,Node b){
return a.r < b.r;
}
int ANS1[N],ANS2[N];
int main(){
n = read();
for(int i = 1;i <= n;i++){
a[i] = read();
b[i] = pos[a[i]];
pos[a[i]] = i;
}
for(int i = 1;i <= n;i++) b[i]++;
int q;
//scanf("%d",&q);
q = read();
for(int i = 1;i <= q;i++){
Q[i].id = i;
//scanf("%d%d",&Q[i].l,&Q[i].r);
Q[i].l = read();Q[i].r = read();
}
sort(Q+1,Q+1+q,cmp1);
int idx = 1;
for(int i = 1;i <= q;i++){
while(idx < Q[i].l){
update(b[idx],1);
idx++;
}
ANS1[Q[i].id] = query(Q[i].l);
}
memset(tree,0,sizeof(tree));
sort(Q+1,Q+1+q,cmp2);
idx = 1;
for(int i = 1;i <= q;i++){
while(idx <= Q[i].r){
update(b[idx],1);
idx++;
}
ANS2[Q[i].id] = query(Q[i].l);
}
for(int i = 1;i <= q;i++){
printf("%d\n",ANS2[i]-ANS1[i]);
}
return 0;
}
P5482
题意:
支 持 三 个 操 作 : ① 加 入 一 条 不 等 式 ; ② 删 除 一 条 不 等 式 ; ③ 询 问 x = k 有 多 少 条 不 等 式 成 立 支持三个操作:①加入一条不等式;②删除一条不等式;③询问x=k有多少条不等式成立 支持三个操作:①加入一条不等式;②删除一条不等式;③询问x=k有多少条不等式成立
思路:
可
以
发
现
③
操
作
的
k
范
围
挺
小
的
,
可
以
维
护
这
个
值
域
范
围
的
树
状
数
组
可以发现③操作的k范围挺小的,可以维护这个值域范围的树状数组
可以发现③操作的k范围挺小的,可以维护这个值域范围的树状数组
即
若
这
个
值
可
以
对
这
条
不
等
式
成
立
就
加
1
即若这个值可以对这条不等式成立就加1
即若这个值可以对这条不等式成立就加1
对
于
添
加
不
等
式
的
操
作
:
对于添加不等式的操作:
对于添加不等式的操作:
①
首
先
一
个
比
较
容
易
的
a
=
0
,
若
b
>
c
则
整
个
值
域
都
加
一
,
否
则
在
整
个
值
域
上
不
操
作
;
①首先一个比较容易的a = 0,若b>c则整个值域都加一,否则在整个值域上不操作;
①首先一个比较容易的a=0,若b>c则整个值域都加一,否则在整个值域上不操作;
②
a
>
0
,
简
单
移
项
可
得
x
>
c
−
b
a
,
先
对
不
等
式
左
边
的
值
判
断
下
如
果
超
过
了
1
e
6
②a > 0,简单移项可得x > \frac{c-b}a,先对不等式左边的值判断下如果超过了1e6
②a>0,简单移项可得x>ac−b,先对不等式左边的值判断下如果超过了1e6
就
不
操
作
了
,
因
为
不
会
询
问
到
;
否
则
v
a
l
和
−
1
e
6
取
个
m
a
x
到
1
e
6
都
是
解
就不操作了,因为不会询问到;否则val和-1e6取个max到1e6都是解
就不操作了,因为不会询问到;否则val和−1e6取个max到1e6都是解
$即这个范围加1(val =
⌊
c
−
b
a
)
⌋
+
1
,
因
为
x
>
4.5
的
整
数
解
都
是
大
于
等
于
5
)
\lfloor \frac{c-b}a) \rfloor+1,因为x > 4.5 的整数解都是大于等于5)
⌊ac−b)⌋+1,因为x>4.5的整数解都是大于等于5)
③
a
<
0
类
似
,
移
项
可
得
x
<
c
−
b
a
,
先
判
断
下
左
边
是
否
已
经
小
于
−
1
e
6
③a < 0类似,移项可得x < \frac{c-b}a,先判断下左边是否已经小于-1e6
③a<0类似,移项可得x<ac−b,先判断下左边是否已经小于−1e6
小
于
了
就
不
操
作
了
,
否
则
−
1
e
6
到
v
a
l
和
1
e
6
取
的
m
a
x
都
是
解
小于了就不操作了,否则-1e6到val和1e6取的max都是解
小于了就不操作了,否则−1e6到val和1e6取的max都是解
这
个
范
围
都
加
1
(
v
a
l
=
⌈
c
−
b
a
⌉
−
1
,
因
为
x
<
5.3
的
整
数
解
都
小
于
等
于
5
)
这个范围都加1(val = \lceil \frac{c-b}a \rceil-1,因为x < 5.3的整数解都小于等于5)
这个范围都加1(val=⌈ac−b⌉−1,因为x<5.3的整数解都小于等于5)
为
了
方
便
去
掉
了
负
数
,
所
有
的
值
都
加
上
了
一
个
偏
移
量
为了方便去掉了负数,所有的值都加上了一个偏移量
为了方便去掉了负数,所有的值都加上了一个偏移量
还
有
一
个
就
是
可
能
会
多
次
删
除
一
个
不
等
式
还有一个就是可能会多次删除一个不等式
还有一个就是可能会多次删除一个不等式
这
题
细
节
蛮
多
的
这题细节蛮多的
这题细节蛮多的
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
const int N = 1e5+10;
const int M = 2e6+10;
const int B = 1e6+1;//偏移量
const int mx = 1e6+B;
//记下第i条不等式进行了什么操作
int idx;
struct Node{
int l,r;
bool st;
}op[N];
//BIT Begin
int tree[M];
int lowbit(int x){
return x&(-x);
}
int query(int x){
int res = 0;
while(x){
res += tree[x];
x -= lowbit(x);
}
return res;
}
void modify(int x,int dx){
while(x <= mx){
tree[x] += dx;
x += lowbit(x);
}
}
void update(int l,int r,int dx){
modify(l,dx);modify(r+1,-dx);
}
//BIT End
void add(int a,int b,int c){
if(a == 0){
if(b > c){
op[++idx].st = 1;
op[idx].l = 1,op[idx].r = mx;
update(op[idx].l,op[idx].r,1);
}else{
op[++idx].st = 0;
}
}else if(a > 0){
int l = (int)floor(((c-b)*1.0)/a) + 1 + B;
if(l > mx) op[++idx].st = 0;
else{
op[++idx].st = 1;
op[idx].l = max(1,l),op[idx].r = mx;
update(op[idx].l,op[idx].r,1);
}
}else{
int r = int(ceil(((c-b)*1.0)/a)) - 1 + B;
if(r < 1) op[++idx].st = 0;
else{
op[++idx].st = 1;
op[idx].l = 1,op[idx].r = min(r,mx);
update(op[idx].l,op[idx].r,1);
}
}
}
void del(int num){
if(op[num].st){
update(op[num].l,op[num].r,-op[num].st);
op[num].st = 0;
}
}
int main(){
int n;scanf("%d",&n);
char s[10];
while(n--){
scanf("%s",s);
if(s[0] == 'A'){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}else if(s[0] == 'D'){
int num;scanf("%d",&num);
del(num);
}else{
int x;scanf("%d",&x);
printf("%d\n",query(x+B));
}
}
return 0;
}