1. 程式人生 > >2018.10.14 loj#516. DP 一般看規律(啟發式合併)

2018.10.14 loj#516. DP 一般看規律(啟發式合併)

傳送門 注意到一種顏色改了之後就不能改回去了。 因此可以啟發式合併。 每次把小的合併給大的。 這樣每個數最多被合併loglog次。 如果維護一棵比較下標的平衡樹的話,對於答案有貢獻的就是每個數與前驅和後繼的差值。 於是就用setset實現啦。 程式碼:

#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; }