题目大意
给一个
n
n
n个正整数的序列
共有
m
m
m次操作
操作
1
1
1:将区间
[
l
,
r
]
[l,r]
[l,r]中所有数变为
x
x
x
操作
2
2
2:询问区间
[
l
,
r
]
[l,r]
[l,r]中不同种类数的个数
n
,
m
≤
1
0
5
,
a
i
≤
1
0
9
n,m\le 10^5,a_i\le 10^9
n,m≤105,ai≤109
s
o
l
u
t
i
o
n
solution
solution:
(分析复杂度视
n
,
m
n,m
n,m同数量级
显然数要离散掉
没有操作 1 1 1或者操作 1 1 1中 l = r l=r l=r我们都可以直接做了(待修改莫队,树套树, c d q cdq cdq分治)
直接考虑树套树以及
c
d
q
cdq
cdq分治的做法
如果没有操作
1
1
1,我们记录一个
p
r
e
[
i
]
pre[i]
pre[i]表示上一个与
a
i
a_i
ai相同的位置
那么询问
[
l
,
r
]
[l,r]
[l,r]其实就是询问对于所有
x
∈
[
l
,
r
]
,
x∈[l,r],
x∈[l,r],满足
p
r
e
[
x
]
<
l
pre[x]<l
pre[x]<l的个数
裸的二维数点。
单点修改我们直接用 s e t set set维护前驱后继就做完了
区间修改?
我们可以发现对于一段相同的数把他变为另一个数会变化的只有这一段数的头和尾
考虑用
s
e
t
set
set维护每一段相同的块
每次修改要做的只是将 l l l和 r r r所在的块分裂,并把中间的块删去,添加一个新的块
可以发现块的个数是
O
(
n
)
O(n)
O(n)的,故这一部分复杂度为
n
l
o
g
n
nlogn
nlogn
后面就是裸的
c
d
q
cdq
cdq分治了
总复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define maxn 100010
int rd()
{
int num = 0;char c = getchar();bool flag = true;
while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
if(flag) return num;else return -num;
}
int n,m,t;
int ans[101000],lk,pre[101000];
int st[101000],pl[101000];
namespace cdq
{
int tr[101000];
void add(int x,int v){for(x++;x<=maxn;x+=x&-x) tr[x] += v;}
int ask(int x){int now=0;for(x++;x;x-=x&-x) now+=tr[x];return now;}
struct data{int op,x,y,val;}a[2001000],tmp[2001000];
void cdq(int l,int r)
{
if(l == r) return;
int mid = (l+r)>>1;
cdq(l,mid);cdq(mid+1,r);
int p = l,q = mid+1,t = 0;
while(p <= mid && q <= r)
if(a[p].x <= a[q].x)
{
if(a[p].op == 1) add(a[p].y,a[p].val);
tmp[++t] = a[p++];
}
else
{
if(a[q].op == 2) ans[a[q].val] -= ask(a[q].y);
if(a[q].op == 3) ans[a[q].val] += ask(a[q].y);
tmp[++t] = a[q++];
}
while(q <= r)
{
if(a[q].op == 2) ans[a[q].val] -= ask(a[q].y);
if(a[q].op == 3) ans[a[q].val] += ask(a[q].y);
tmp[++t] = a[q++];
}
rep(i,l,p-1) if(a[i].op == 1) add(a[i].y,-a[i].val);
while(p <= mid) tmp[++t] = a[p++];
rep(i,l,r) a[i] = tmp[i-l+1];
}
void add(int op,int x,int y,int val){a[++t].op = op;a[t].x = x;a[t].y = y;a[t].val = val;}
}using namespace cdq;
#define hash Hash
namespace hash
{
int cnt = 0;
unordered_map<int,int>g;
int getid(int x){if(!g[x]) return g[x]=++cnt;else return g[x];}
}using namespace hash;
namespace bwork
{
#define IT1 set<block>::iterator
#define IT2 set<int>::iterator
struct block{
int l,r,v;
bool operator < (const block &x)const {
return l < x.l;
}
};
set<block>all,sp[201000];//all存所有颜色块,sp存单个颜色
set<int>tmp;//tmp存某次修改要修改的序列
int cas;
IT1 getblock(set<block> &x,int pos)
{
return --x.upper_bound( (block){pos,0,0} );
}
void insert(int l,int r,int v)
{
block now = (block){l,r,v};
all.insert(now);
sp[v].insert(now);
}
void del(IT1 it)
{
sp[it->v].erase(getblock(sp[it->v],it->l));
all.erase(it);
}
IT1 spt(int pos)
{
if(pos > n) return all.end();
IT1 it = getblock(all,pos);
int l = it->l,r = it->r,v = it->v;
if(pos == l) return it;
del(it);
insert(l,pos-1,v);
insert(pos,r,v);
return getblock(all,pos);
}
int get_ne(int pos)
{
IT1 it = getblock(all,pos);
int v = it->v;
it = getblock(sp[v],pos);
if(++it == sp[v].end()) return 0;
else return it->l;
}
int get_pre(int pos)
{
IT1 it = getblock(all,pos);
int v = it->v;
it = getblock(sp[v],pos);
if(pos > it->l) return pos-1;
if(it == sp[v].begin()) return 0;
return ((--it)->r);
}
void change(int x)
{
int la = get_pre(x);
if(la == pre[x]) return;
if(pre[x] != -1) cdq::add(1,x,pre[x],-1);
cdq::add(1,x,pre[x] = la,1);
}
void update(int l,int r,int v)
{
IT1 en = spt(r+1),st = spt(l);
for(IT1 it = st;it != en;it++)
{
tmp.insert(it->l),tmp.insert(get_ne(it->r));
}
for(IT1 it = st;it != en;del(it++));
insert(l,r,v);
tmp.insert(get_ne(r));
for(IT2 it = tmp.begin();it != tmp.end();it++) if((*it) != 0) change((*it));
tmp.clear();
}
}using namespace bwork;
void init()
{
n = rd();m = rd();
rep(i,1,n) st[i] = hash::getid(rd());
rep(i,1,n) if(!pl[st[i]]) pre[i] = 0,pl[st[i]] = i;
else pre[i] = pl[st[i]],pl[st[i]] = i;
rep(i,1,n) cdq::add(1,i,pre[i],1);
int now = 1;
rep(i,2,n)
if(st[i] != st[i-1]) bwork::insert(now,i-1,st[i-1]),now = i;
bwork::insert(now,n,st[n]);
}
int main()
{
freopen("third.in","r",stdin);
freopen("third.out","w",stdout);
init();
rep(i,1,m)
{
int op = rd(),l = rd(),r = rd(),x;
if(op == 2) cdq::add(2,l-1,l-1,++lk),cdq::add(3,r,l-1,lk);
else x = getid(rd()),bwork::update(l,r,x);
}
cdq::cdq(1,t);
rep(i,1,lk) printf("%d\n",ans[i]);
return 0;
}