雖然T2 作法假了 不過稍微改一下 就能夠寫luogu另一道相似的題目node
屢次查詢一個區間內 相同數字 最遠的距離 c++
那麼 咱們再考慮 查詢區間內 相同數字 最近的距離git
看似特別相同的兩個問題 咱們思考一下 是否可使用同一種方法寫過ui
暴力寫過是沒有意義的 或許你擡槓你分比較高 這裏不討論了spa
確實 莫隊和分塊 均可以寫過 可是 我確實是 想到了線段樹的作法code
那麼第一問是今天模擬賽的題目 我確實寫了個一個線段樹 很快就寫完了 過了大小樣例 就沒再管 blog
下考場以後 才知道 樣例的數據確實很水 讓我很巧的避免了全部 我代碼中錯誤的地方 排序
那麼不妨我先來分析 第二問的作法 能夠借鑑 CF522D Closest Equals 這個題目get
此時 查詢最小距離 顯然咱們能夠直接 維護離他最近的距離便可it
由於 最小距離 具備最優性 考慮此時只維護左邊第一個和他相同的數字出現的位置
對於 詢問咱們不妨將詢問離線 按照右端點從小到大排序 維護一下區間最小值便可 看code吧
//查詢一個區間內 相同的數字的之間的最小距離 //首先將 詢問離線 按右端點排序 對於每個x 咱們只關心 離他最近的x 那麼維護左邊第一個x出現的位置 //線段樹維護區間最小值便可 #include <bits/stdc++.h> using namespace std; template<typename T>inline void read(T &x) { x=0;T f=1,ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x*=f; } const int maxn=510000; const int inf=1e9; int n,m,x,q,ans[maxn],last[maxn],p[maxn]; map<int,int>mp; struct node { int l,r,id; }s[maxn]; int cmp(node x,node y){return x.r<y.r;} struct Tree { int l,r,minn; }t[4*maxn]; void build(int p,int L,int R) { t[p].l=L;t[p].r=R;t[p].minn=inf; if(L>=R)return ; int mid=(t[p].l+t[p].r)>>1; build(2*p,L,mid); build(2*p+1,mid+1,R); } inline void update(int p,int pos,int num) { if(t[p].l==t[p].r&&t[p].l==pos){t[p].minn=min(t[p].minn,num);return ;} int mid=(t[p].l+t[p].r)>>1; if(pos<=mid)update(2*p,pos,num); else update(2*p+1,pos,num); t[p].minn=min(t[2*p].minn,t[2*p+1].minn); } inline int query(int p,int L,int R) { if(L<=t[p].l&&R>=t[p].r) return t[p].minn; int mid=(t[p].l+t[p].r)>>1; int res=inf; if(L<=mid)res=min(res,query(2*p,L,R)); if(R>mid)res=min(res,query(2*p+1,L,R)); return res; } int main() { // freopen("1.in","r",stdin); // freopen("far.in","r",stdin); // freopen("far.out","w",stdout); read(n); read(q); build(1,1,n); for(int i=1;i<=n;i++) { read(x); if(mp[x]) p[i]=mp[x],mp[x]=i; else mp[x]=i,p[i]=0; } for(int i=1;i<=q;i++) { read(s[i].l); read(s[i].r); s[i].id=i; } sort(s+1,s+q+1,cmp); int r=1; for(int i=1;i<=q;i++) { while(r<=s[i].r) { if(p[r]) update(1,p[r],r-p[r]); r++; } int res=query(1,s[i].l,r-1); if(res>=inf) ans[s[i].id]=-1; else ans[s[i].id]=res; } for(int i=1;i<=q;i++) printf("%d\n",ans[i]); return 0; }
或許 你會認爲第一問和第二問不是同樣的嗎 考慮此時咱們僅僅維護 相鄰答案必定是錯的
那麼考慮維護什麼呢 維護一個離他最遠的點 你不難想到 會直接考慮 維護第一次出現的位置
可是顯然 咱們會出現不少問題 不過我確實考場上是這麼作的 不過線段樹再去訂正這個東西實在是太困難了
考慮 爲何錯了 對於一組數據 如今在查詢區間內 存在兩個相同的數字 可是區間左端點以外依舊 存在一個點 而且是第一次出現的
那麼 此時個人答案是0 雖然這種作法會過濾到不合法的狀況 可是 咱們不難想到 會遺漏不少答案 因此作法存在缺陷。
不過 回滾莫隊和分塊確實能夠解決這個問題呢。 今天下午訂正8