EOJ2458(離散化+線段樹)
阿新 • • 發佈:2019-02-13
這題題意就是問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);
}
}