ps:最近都在A一些数据结构题,感觉又要变笨了QAQ(本来就很笨)
题目概述
给出一个长度为n的序列和m个操作,每个操作会把所有x改成y,每次操作过后输出min{j-i|a[i]=a[j]}。
解题报告
我们会发现这样一个性质:一种数字变成另外一种数字,就不可能单独变回来了。所以一种数字一旦消失是撤销不了的(其他数字变成该数字不算)。那么也就是说我们可以利用平衡树启发式合并每种数字(先离散),然后查询一下最小距离即可。
不知道是不是因为打了SBT,我竟然rank4了!
示例程序
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100000,maxm=100000,maxt=maxn+2*maxm,MAXINT=((1<<30)-1)*2+1;
int n,m,a[maxn+5],b[maxt+5],x[maxm+5],y[maxm+5],MIN;
struct node
{
node* son[2];int si,key;
node(int k,node* p,int s=1) {si=s;key=k;son[0]=son[1]=p;}
bool cmp(int k) {return k>=key;}
void Pushup() {si=son[0]->si+1+son[1]->si;}
};
node nil(0,&nil,0);
typedef node* P_node;
P_node null=&nil,ro[maxt+5];
void Rotate(P_node &p,bool d)
{
P_node t=p->son[d^1];p->son[d^1]=t->son[d];t->son[d]=p;
p->Pushup();t->Pushup();p=t;
}
void Maintain(P_node &p,bool fl)
{
P_node L=p->son[0],R=p->son[1];
if (!fl)
if (L->son[0]->si>R->si) Rotate(p,1); else
if (L->son[1]->si>R->si) Rotate(p->son[0],0),Rotate(p,1); else
return;
else
if (R->son[1]->si>L->si) Rotate(p,0); else
if (R->son[0]->si>L->si) Rotate(p->son[1],1),Rotate(p,0); else
return;
Maintain(p->son[0],0);Maintain(p->son[0],1);
Maintain(p->son[1],0);Maintain(p->son[1],1);
Maintain(p,0);Maintain(p,1);
}
void Insert(P_node &p,int k)
{
if (p==null) {p=new node(k,null);return;}
int d=p->cmp(k);Insert(p->son[d],k);
p->Pushup();Maintain(p,d);
}
int getpre(P_node p,int k)
{
if (p==null) return -MAXINT;
if (k>p->key) return max(p->key,getpre(p->son[1],k)); else
return getpre(p->son[0],k);
}
int getsuf(P_node p,int k)
{
if (p==null) return MAXINT;
if (k<p->key) return min(p->key,getsuf(p->son[0],k)); else
return getsuf(p->son[1],k);
}
int Ask(P_node A,P_node B)
{
if (B==null) return MAXINT;
int now=MAXINT,pre=getpre(A,B->key),suf=getsuf(A,B->key);
if (pre!=-MAXINT) now=min(now,B->key-pre);
if (suf!=MAXINT) now=min(now,suf-B->key);
return min(now,min(Ask(A,B->son[0]),Ask(A,B->son[1])));
}
void Join(P_node &A,P_node B)
{
if (B==null) return;Insert(A,B->key);
Join(A,B->son[0]);Join(A,B->son[1]);
}
int Find(int x)
{
int L=1,R=b[0];
while (L<=R)
{
int mid=L+(R-L>>1);
if (x==b[mid]) return mid;
if (x<b[mid]) R=mid-1; else L=mid+1;
}
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[++b[0]]=a[i];
for (int i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]),b[++b[0]]=x[i],b[++b[0]]=y[i];
sort(b+1,b+b[0]+1);
b[0]=1;for (int i=2;i<=n+2*m;i++) if (b[i]>b[i-1]) b[++b[0]]=b[i];
for (int i=1;i<=b[0];i++) ro[i]=null;
for (int i=1;i<=n;i++) Insert(ro[Find(a[i])],i);
MIN=MAXINT;for (int i=1;i<=b[0];i++) MIN=min(MIN,Ask(ro[i],ro[i]));
for (int i=1;i<=m;i++)
{
int A=Find(x[i]),B=Find(y[i]);
if (A==B) {printf("%d\n",MIN);continue;}
if (ro[A]->si>ro[B]->si)
{
MIN=min(MIN,Ask(ro[A],ro[B]));
Join(ro[A],ro[B]);ro[B]=ro[A];ro[A]=null;
} else
{
MIN=min(MIN,Ask(ro[B],ro[A]));
Join(ro[B],ro[A]);ro[A]=null;
}
printf("%d\n",MIN);
}
return 0;
}