1. 程式人生 > 實用技巧 >【NOIP2017模擬8.8A組】Trip(trip)

【NOIP2017模擬8.8A組】Trip(trip)

Description

多年之後,worldwideD厭倦競爭,隱居山林。
他的家鄉開始發展起了旅遊業,在一條很長的主幹道上,有N個旅遊景點,按順序編號為1到N。根據遊客們網上的評分,第i個景點有一個評估值a[i],為了區分開不同的景點,評估值是兩兩不同的。
今天有M組遊客前來旅遊,第i組遊客選擇遍歷景點Li到景點Ri這一段路。他們搜到Li到Ri的所有評估值,如果對於景點j(Li≤j≤Ri),不存在景點x(Li≤x<j)滿足a[x]>a[j]或不存在景點y(j<y≤Ri)滿足a[y]>a[j],那麼他們會進入景點j。
現在worldwideD想知道,每組遊客會去多少個景點。

Input

第一行兩個整數N,M,意義見題面。
接下來一行N個整數,第i個是a[i],意義見題面。
接下來M行,第i行兩個整數Li,Ri,意義見題目。

Sample Input

6 4
3 1 7 4 5 2
1 5
2 5
2 6
4 6

Output

M行,第i行表示第i組遊客去的景點個數。

Sample Output

3
3
4
3

先建出笛卡爾樹
發現
(1)有貢獻的景點在L到R的樹上路徑
(2)並且對於一個景點,如果L在其左子樹或R在其右子樹,則該景點有貢獻
Tarjan求lca,預處理每個景點到根路徑上的經過的左右兒子的個數即可

笛卡爾樹:滿足中序遍歷是原序列,是二叉樹,父親節點優先順序大於子節點

O(n)建法:加進一個點i,從最後一個點往上找到第一個優先順序大於他的點x,father[i]=x;left_son[i]=right_son[x];right_son[x]=i;
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,a[1000001],L[1000001],R[1000001];
int pf[2][1000001],pl[2][1000001],pn[2][1000001],father[1000001];
int dc[1000001][2],wei[1000001],lca[1000001],fa[1000001],p5[1000001];
int zuo[1000001],you[1000001];
int read() { int x=0,sig=1; char c; for (c=getchar();c<'0' || c>'9';c=getchar()) if (c=='-') sig=-1; for (;c>='0' && c<='9';c=getchar()) x=x*10+c-48; return x*sig; } void write(int x) { if (!x) putchar('0');else { char s[10]; int i,j=0; for (;x>0;x/=10) s[j++]=x%10; for (i=j-1;i>=0;i--) putchar(s[i]+48); } putchar('\n'); } int find(int x){ if(fa[x]==x)return x; return fa[x]=find(fa[x]); } void jia(int x,int y,int z){ if(!pf[z][x])pf[z][x]=y; else pn[z][pl[z][x]]=y; pl[z][x]=y; } void dg(int x){ if(dc[x][0]){ zuo[dc[x][0]]=zuo[x]+1;you[dc[x][0]]=you[x];dg(dc[x][0]); } if(dc[x][1]){ zuo[dc[x][1]]=zuo[x];you[dc[x][1]]=you[x]+1;dg(dc[x][1]); } for(int i=pf[0][x];i!=0;i=pn[0][i]){ if(fa[R[i]]){ find(R[i]); lca[i]=father[fa[R[i]]]; } } for(int i=pf[1][x];i!=0;i=pn[1][i]){ if(fa[L[i]]){ find(L[i]); lca[i]=father[fa[L[i]]]; } }fa[x]=x;fa[dc[x][0]]=x;fa[dc[x][1]]=x; } int main(){ n=read();m=read(); for(int i=1;i<=n;i++){ a[i]=read(); int u=i-1; while(u!=0&&a[u]<a[i])u=father[u]; if(dc[u][1]){ dc[i][0]=dc[u][1]; father[dc[u][1]]=i; }dc[u][1]=i; father[i]=u; } for(int i=1;i<=m;i++){ L[i]=read();R[i]=read(); jia(L[i],i,0);jia(R[i],i,1); }dg(dc[0][1]); for(int i=1;i<=m;i++){if(!lca[i])lca[i]=L[i]; int ans=zuo[L[i]]-zuo[lca[i]]+you[R[i]]-you[lca[i]]+1; write(ans); } return 0; }