1. 程式人生 > >[BZOJ]5042: LWD的分科島 笛卡爾樹+LCA

[BZOJ]5042: LWD的分科島 笛卡爾樹+LCA

Description

大家都知道在文理分科的時候總是讓人糾結的,糾結的當然不只是自己。比如 YSY 就去讀了文科, LWD 知道了很氣。於是他就去卡了 BZOJ 測評機, 晚上他做了一個謎一樣的夢,自己在一座全是 YSY 的分科島。這裡有 YSY 草, YSY 花, YSY 糖……每個 YSY 都有一個美( Ti)麗( Zhong)值。當然沒有小於零的體重啦!LWD 於是不惜重金賣肉想買下這座島,可是分科島的島主,是一位忠實的區間問題愛好者。他想把小島傳給一個謎一樣的愛好者,所以島主給了 LWD 一個終極挑戰——選出一片區域中最美麗的 YSY。可是島主的審美觀不像 YYR那麼專一,他有時喜歡現代美——最輕的,有時喜歡唐代美——最重的。這讓被歡喜衝昏了頭腦(血液集中在下半身)的 LWD 十分苦惱。他要在規定時間內完成挑戰贏得買島的權利,於是只有求助 DalaoYYR,可是 YYR 要準備課件啊。只有比 YYR 弱很多的你能夠幫他了。挑戰內容如下島主將把 N 個 YSY 擺成一個條形,並給出所有 YSY 的美麗值。挑出多少個就要看島主心情了,他覺得 LWD 是條漢子就會給出很多很多的 YSY 滿足他。島主將給出 Q 個考驗,詢問內容是在給定區間內求出最美麗的 YSY。你已經瞭解規則了,開始你的表演吧!

題解:

先建出笛卡爾樹。
笛卡爾樹具有這樣的性質:每個點有兩個權值,只看第一個權值,這棵樹滿足堆的性質;只看第二個權值,這棵樹滿足二叉搜尋樹的性質。
對於這道題目,第一個權值是就是美麗度,第二個權值是位置下標,那麼區間最值就是兩個端點的LCA的值。
所以只需要用Tarjan求LCA,就可以在接近線性時間解決問題。
最後一個問題就是如何建樹,在第二個權值有序的情況下,建樹是線性複雜度的,用一個棧維護當前樹的最右邊一條鏈即可。
程式碼抄了別人的io優化。

程式碼:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int> const int Maxn=3000010; const int Maxm=1500010; const int inf=2147483647; char pbuf[100000] , *pp = pbuf; inline void push(const char ch) { if(pp == pbuf + 100000) fwrite(pbuf , 1 , 100000 , stdout) , pp = pbuf; *pp ++ = ch; } inline void flush() { fwrite(pbuf , 1 , pp - pbuf , stdout
); } inline void write(int x) { static char sta[30]; int tot = 0; if(!x) push('0'); while(x) sta[++tot] = x % 10 + '0' , x /= 10; while(tot) push(sta[tot -- ]); push('\n'); } inline char nc() { static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read() { char ch=nc();int sum=0; while(!isdigit(ch))ch=nc(); while(isdigit(ch))sum=((sum+(sum<<2))<<1)+(ch^48),ch=nc(); return sum; } bool vis[Maxn]; int n,m,a[Maxn],fa[Maxn],sta[Maxn],top,ans[Maxm],root; struct Query{int o,x,y;}q[Maxm]; struct Edge{int y,next,id;}e[Maxm<<1]; int last[Maxn],len=0; void ins(int x,int y,int id) { int t=++len; e[t].y=y;e[t].id=id;e[t].next=last[x];last[x]=t; } int lc[Maxn],rc[Maxn]; int findfa(int x){return((fa[x]==x)?x:fa[x]=findfa(fa[x]));} void Tarjan(int x) { vis[x]=true; if(lc[x])Tarjan(lc[x]),fa[lc[x]]=x; if(rc[x])Tarjan(rc[x]),fa[rc[x]]=x; for(int i=last[x];i;i=e[i].next) { int y=e[i].y; if(vis[y])ans[e[i].id]=findfa(y); } } int main() { n=read(),m=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=m;i++)q[i].o=read(),q[i].x=read(),q[i].y=read(); sta[top=1]=root=1; for(int i=2;i<=n;i++) { int x=0; while(top&&a[sta[top]]>=a[i])x=sta[top--]; if(!top)root=i,lc[i]=x; else lc[i]=x,rc[sta[top]]=i; sta[++top]=i; } while(top>1)rc[sta[top-1]]=sta[top],top--; for(int i=1;i<=m;i++)if(q[i].o==1)ins(q[i].x,q[i].y,i),ins(q[i].y,q[i].x,i); for(int i=1;i<=n;i++)fa[i]=i; Tarjan(root); memset(last,0,sizeof(last));len=0; memset(vis,false,sizeof(vis)); memset(lc,0,sizeof(lc)); memset(rc,0,sizeof(rc)); sta[top=1]=root=1; for(int i=2;i<=n;i++) { int x=0; while(top&&a[sta[top]]<=a[i])x=sta[top--]; if(!top)root=i,lc[i]=x; else lc[i]=x,rc[sta[top]]=i; sta[++top]=i; } while(top>1)rc[sta[top-1]]=sta[top],top--; for(int i=1;i<=m;i++)if(q[i].o==2)ins(q[i].x,q[i].y,i),ins(q[i].y,q[i].x,i); for(int i=1;i<=n;i++)fa[i]=i; Tarjan(root); for(int i=1;i<=m;i++)write(a[ans[i]]); flush(); }