2018.10.14 loj#516. DP 一般看規律(啟發式合併)
阿新 • • 發佈:2018-12-15
傳送門 注意到一種顏色改了之後就不能改回去了。 因此可以啟發式合併。 每次把小的合併給大的。 這樣每個數最多被合併次。 如果維護一棵比較下標的平衡樹的話,對於答案有貢獻的就是每個數與前驅和後繼的差值。 於是就用實現啦。 程式碼:
#include<bits/stdc++.h>
#define N 100005
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans= (ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,m,tot=0,ans=2147483647;
map<int,set<int> >S;
inline void query(int i,int pos){
set<int>::iterator it=S[i].lower_bound(pos);
if(it!=S[i].end())ans=min(ans,(*it)-pos);
if(it!=S[i].begin())--it,ans=min(ans,pos- (*it));
}
int main(){
n=read(),m=read();
for(int val,i=1;i<=n;++i)query((val=read()),i),S[val].insert(i);
while(m--){
int x=read(),y=read();
if(x==y){printf("%d\n",ans);continue;}
if(S[x].size()>S[y].size())swap(S[x],S[y]);
for(set<int>::iterator it=S[x].begin();it!=S[x].end() ;++it)query(y,(*it)),S[y].insert(*it);
S[x].clear(),printf("%d\n",ans);
}
return 0;
}