1. 程式人生 > >EOJ2458(離散化+線段樹)

EOJ2458(離散化+線段樹)

這題題意就是問n個點序列,從小到大排列,問區間裡最長的相等點的長度是多少。那麼我們很容易想到線段樹,將相同點相連即使一條線段,然後問區間裡線段最長的是多少。因為題目給的是1 ≤ n, q ≤ 100000,所以直接建樹勢必複雜度將會很大,因此這裡我們對初始資料先進行離散化。

具體操作就是將資料中相同的點放進一個點集,並用inf陣列記錄下每個點的點集下標,在建樹的時候,直接通過每個點集求出max值。在查詢的時候直接套用query模板,最後取得max值就OK了。
最後通過inf陣列直接找出區間端點所在點集,從而判斷區間覆蓋了多少個點集,然後根據具體情況進行判斷找出最大值就可以AC。

AC程式碼:

#include <iostream>
#include <cstdio> using namespace std; struct ee { int l; int r; int max; }; ee node[300010]; struct seg { int beg; int end; }; seg tree[400010]; int a[100001]; int inf[100001]; void build(int left,int right,int o) { node[o].l=left; node[o].r=right; if (left==right) { int
k=left; node[o].max=tree[k].end-tree[k].beg+1; return; } int mid=(left+right)/2; build(left,mid,o*2); build(mid+1,right,(o*2)+1); node[o].max=max(node[o*2].max,node[o*2+1].max); } int query(int left,int right,int o) { if (node[o].l==left&&node[o].r==right) return
node[o].max; if (right<=node[o*2].r) return query(left,right,o*2); if (left>=node[o*2+1].l) return query(left,right,o*2+1); int a=query(left,node[o*2].r,o*2); int b=query(node[o*2+1].l,right,o*2+1); return max(a,b); } int main() { int n,m,pre,k; scanf("%d",&n); while (n!=0) { scanf("%d",&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); pre=0;k=0; for (int i=1;i<=n;i++) { if (a[i]!=pre) { pre=a[i]; k++; tree[k].beg=i; tree[k].end=i; } else tree[k].end=i; inf[i]=k; } build(1,k,1); while (m--) { int a,b,h1,h2; scanf("%d%d",&a,&b); h1=inf[a]; h2=inf[b]; if (h1==h2) printf("%d\n",b-a+1);//在同一條線段上 else//多個線段上 { int n1=tree[h1].end-a+1;int n2=0; int n3=b-tree[h2].beg+1; if (h2-h1>1) n2=query(h1+1,h2-1,1); printf("%d\n",max(max(n1,n3),n2)); } } scanf("%d",&n); } }