[BZOJ]5042: LWD的分科岛 笛卡尔树+LCA

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36797646/article/details/84971776

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();
}

猜你喜欢

转载自blog.csdn.net/baidu_36797646/article/details/84971776