【bzoj2120】数颜色【树套树+平衡树 树状数组套权值线段树】
2120: 数颜色
Description
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?
Input
第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。
Output
对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。
题意:有一个区间,支持两种操作:修改一个值,查询一个区间内有多少个不同的数。
可以对于每一个位置,维护pre,即这个值前面最后一次出现的位置,和sub,即这个值后面第一次出现的位置。查询[l,r]区间有多少个不同的数,就是查询[l,r]区间有多少个位置的pre<l。很显然,这个东西可以用主席树解决,询问时差分一下即可。带修改操作也真是恶心,改成树状数组套权值线段树。
再来说一下怎么维护pre和sub。要把权值离散化一下,再开n棵平衡树对应每种权值。修改时再各种乱搞,把各种贡献加加减减的,并找到新的值的pre和sub。细节详见代码。我打了一棵替罪羊树,发现还真是挺快的,第一次进RANK前3页。
坑啊!我的数组开成10000,不知怎么的就WA了一个上午!改成11000就AC了。不是应该RE的吗 = =
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
inline int rd()
{
char ch=getchar();
int ret=0,f=1;
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ret=ret*10+ch-'0';
ch=getchar();
}
return ret*f;
}
const int N=11005;
int n,m,cnt,a[N],hash[2*N],pre[N],sub[N],last[N],root[N];
int sumv[N*100],lc[N*100],rc[N*100],L[10005],R[10005];
int mempool[2*N],siz[2*N],tot[2*N],key[2*N],del[2*N],pos[2*N],ch[2*N][2];
struct query
{
char s[5];
int l,r;
}q[N];
int getid(int x)
{
return lower_bound(hash+1,hash+hash[0]+1,x)-hash;
}
int lowbit(int x)
{
return x&(-x);
}
struct ScapeGoatTree
{
int root;
int *goat;
int rnk(int x)
{
int k=root,ret=1;
while(k)
{
if(x<=key[k]) k=ch[k][0];
else
{
ret+=siz[ch[k][0]]+del[k];
k=ch[k][1];
}
}
return ret;
}
int kth(int x)
{
if(x<1||x>siz[root]) return 0;
int k=root;
while(k)
{
if(del[k]&&x==siz[ch[k][0]]+1) return key[k];
else if(x<=siz[ch[k][0]]+del[k]) k=ch[k][0];
else
{
x-=siz[ch[k][0]]+del[k];
k=ch[k][1];
}
}
}
void dfs(int k)
{
if(!k) return;
dfs(ch[k][0]);
if(del[k]) pos[++pos[0]]=k;
else mempool[++mempool[0]]=k;
dfs(ch[k][1]);
}
void build(int &k,int l,int r)
{
if(l>r)
{
k=0;
return;
}
int mid=(l+r)/2;
k=pos[mid];
build(ch[k][0],l,mid-1);
build(ch[k][1],mid+1,r);
siz[k]=siz[ch[k][0]]+siz[ch[k][1]]+1;
tot[k]=tot[ch[k][0]]+tot[ch[k][1]]+1;
}
void rebuild(int &k)
{
pos[0]=0;
dfs(k);
build(k,1,pos[0]);
}
void insert(int &k,int x)
{
if(!k)
{
k=mempool[mempool[0]--];
key[k]=x;
siz[k]=tot[k]=del[k]=1;
ch[k][0]=ch[k][1]=0;
return;
}
siz[k]++;
tot[k]++;
if(x<=key[k]) insert(ch[k][0],x);
else insert(ch[k][1],x);
if(siz[k]*0.75<max(siz[ch[k][0]],siz[ch[k][1]]))
goat=&k;
}
void insert(int x)
{
goat=NULL;
insert(root,x);
if(goat) rebuild(*goat);
}
void remove(int k,int x)
{
if(del[k]&&x==siz[ch[k][0]]+1)
{
siz[k]--;
del[k]=0;
return;
}
siz[k]--;
if(x<=siz[ch[k][0]]+del[k])
remove(ch[k][0],x);
else remove(ch[k][1],x-siz[ch[k][0]]-del[k]);
}
void remove(int x)
{
remove(root,rnk(x));
if(siz[root]<tot[root]*0.75) rebuild(root);
}
}sgt[N];
void update(int &o,int l,int r,int k,int v)
{
if(!o) o=++cnt;
sumv[o]+=v;
if(l==r) return;
int mid=(l+r)/2;
if(k<=mid) update(lc[o],l,mid,k,v);
else update(rc[o],mid+1,r,k,v);
}
int query(int l,int r,int k)
{
if(l==r) return 0;
int mid=(l+r)/2;
if(k<=mid)
{
for(int i=1;i<=L[0];i++) L[i]=lc[L[i]];
for(int i=1;i<=R[0];i++) R[i]=lc[R[i]];
return query(l,mid,k);
}
else
{
int sum=0;
for(int i=1;i<=L[0];i++)
{
sum-=sumv[lc[L[i]]];
L[i]=rc[L[i]];
}
for(int i=1;i<=R[0];i++)
{
sum+=sumv[lc[R[i]]];
R[i]=rc[R[i]];
}
return sum+query(mid+1,r,k);
}
}
int solvequery(int l,int r)
{
L[0]=R[0]=0;
for(int i=l-1;i;i-=lowbit(i)) L[++L[0]]=root[i];
for(int i=r;i;i-=lowbit(i)) R[++R[0]]=root[i];
return query(0,n,l);
}
int main()
{
for(int i=1;i<=20000;i++) mempool[i]=i;
mempool[0]=20000;
n=rd(),m=rd();
for(int i=1;i<=n;i++)
hash[++hash[0]]=a[i]=rd();
for(int i=1;i<=m;i++)
{
scanf("%s",q[i].s);
q[i].l=rd(),q[i].r=rd();
if(q[i].s[0]=='R') hash[++hash[0]]=q[i].r;
}
sort(hash+1,hash+hash[0]+1);
hash[0]=unique(hash+1,hash+hash[0]+1)-hash-1;
for(int i=1;i<=n;i++)
{
a[i]=getid(a[i]);
pre[i]=last[a[i]];
if(last[a[i]]) sub[last[a[i]]]=i;
last[a[i]]=i;
sgt[a[i]].insert(i);
for(int j=i;j<=n;j+=lowbit(j))
update(root[j],0,n,pre[i],1);
}
for(int i=1;i<=m;i++)
{
if(q[i].s[0]=='Q')
{
L[0]=R[0]=0;
for(int j=q[i].l-1;j;j-=lowbit(j)) L[++L[0]]=root[j];
for(int j=q[i].r;j;j-=lowbit(j)) R[++R[0]]=root[j];
printf("%d\n",query(0,n,q[i].l));
}
else
{
q[i].r=getid(q[i].r);
for(int j=q[i].l;j<=n;j+=lowbit(j))
update(root[j],0,n,pre[q[i].l],-1);
if(pre[q[i].l]) sub[pre[q[i].l]]=sub[q[i].l];
if(sub[q[i].l])
{
for(int j=sub[q[i].l];j<=n;j+=lowbit(j))
update(root[j],0,n,q[i].l,-1);
for(int j=sub[q[i].l];j<=n;j+=lowbit(j))
update(root[j],0,n,pre[q[i].l],1);
pre[sub[q[i].l]]=pre[q[i].l];
}
sgt[a[q[i].l]].remove(q[i].l);
sgt[q[i].r].insert(q[i].l);
a[q[i].l]=q[i].r;
pre[q[i].l]=sgt[q[i].r].kth(sgt[q[i].r].rnk(q[i].l)-1);
sub[q[i].l]=sgt[q[i].r].kth(sgt[q[i].r].rnk(q[i].l)+1);
for(int j=q[i].l;j<=n;j+=lowbit(j))
update(root[j],0,n,pre[q[i].l],1);
if(pre[q[i].l]) sub[pre[q[i].l]]=q[i].l;
if(sub[q[i].l])
{
for(int j=sub[q[i].l];j<=n;j+=lowbit(j))
update(root[j],0,n,pre[q[i].l],-1);
for(int j=sub[q[i].l];j<=n;j+=lowbit(j))
update(root[j],0,n,q[i].l,1);
pre[sub[q[i].l]]=q[i].l;
}
}
}
return 0;
}