蓝桥杯-压缩变换(可持久化线段树)
题目
获取一段区间内无重复数字的种类
思路
经典在线可持久化线段树,或者离线树状数组
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int N = 1e5+5;
struct node
{
int l,r,sum;
}tr[N<<5];
int tot,root[N];
int build(int l,int r)
{
int cur = ++tot;
tr[cur].sum = 0;
tr[cur].l = tr[cur].r = 0;
if(l == r) return cur;
int mid = l + r >> 1;
tr[cur].l = build(l,mid);
tr[cur].r = build(mid+1,r);
return cur;
}
int update(int x ,int q ,int val ,int l,int r)
{
int cur = ++tot;
tr[cur] = tr[q];
tr[cur].sum += val;
if(l == r) return cur;
int mid = l + r >> 1;
if(x <= mid)
tr[cur].l = update(x,tr[q].l,val,l,mid);
else
tr[cur].r = update(x,tr[q].r,val,mid+1,r);
return cur;
}
int query(int x,int cur,int l,int r)
{
if(l == r) return tr[cur].sum;
int mid = l + r >> 1;
if(x <= mid)
return tr[tr[cur].r].sum + query(x,tr[cur].l,l,mid);
else
return query(x,tr[cur].r,mid+1,r);
}
int n,a[N];
map<int,int> mp;
int main()
{
cin>>n;
for(int i = 1 ; i <= n; i ++)
cin>>a[i];
root[0] = build(1,n);
for(int i = 1 ; i <= n; i ++)
{
if(!mp.count(a[i]))
root[i] = update(i,root[i-1],1,1,n);
else
{
int t = update(mp[a[i]],root[i-1],-1,1,n);
root[i] = update(i,t,1,1,n);
}
mp[a[i]] = i;
}
mp.clear();
for(int i = 1 ; i <= n; i ++)
{
if(!mp.count(a[i]))
cout<<-a[i]<<" ";
else
cout<<query(mp[a[i]]+1,root[i-1],1,n)<<" ";
mp[a[i]] = i;
}
return 0;
}