zoukankan      html  css  js  c++  java
  • 小米网络赛 热身赛 H题 Equivalent Prefixes

    Pro:
    https://ac.nowcoder.com/acm/contest/8409/H
    给出两个排列同构的定义
    对于任意区间([l,r]) (RMQ_A(l,r)=RMQ_B(l,r))
    (RMQ)表示这个区间的最小值的下标
    给定两个排列
    求它们的最大同构前缀

    Sol:
    读完题就有一种浓浓的笛卡尔树的味道
    事实上也确实如此
    只需要判断它们的笛卡尔树是否同构即可
    对于笛卡尔树,显然有一种O(rmq)的建树方式
    在这个基础上加一个二分即可

    #include<bits/stdc++.h>
    #define M 22
    #define N 550000
    #define db double
    #define ll long long
    #define ldb long double
    #define ull unsigned long long
    using namespace std;
    const int h=3,ki=149,mo=998244353;
    inline int inc(int x,int k){x+=k;return x<mo?x:x-mo;}
    inline int dec(int x,int k){x-=k;return x>=0?x:x+mo;}
    inline int read()
    {
    	char ch=0;int x=0,flag=1;
    	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
    	return x*flag;
    }
    inline void write(int x)
    {
    	if(!x)return (void)putchar(48);
    	if(x<0)putchar(45),x=-x;
    	int len=0,p[20];
    	while(x)p[++len]=x%10,x/=10;
    	for(int i=len;i>=1;i--)putchar(p[i]+48);
    }
    const db eps=1e-7,inf=1e9+7,pi=acos(-1);
    inline db Read(){db x;scanf("%lf",&x);return x;}
    inline void Write(db x){printf("%lf",x);}
    int a[N],b[N],lg[N],f[N][M],g[N][M];
    int queryf(int l,int r)
    {
    	int k=lg[r-l+1],x=f[l][k],y=f[r-(1<<k)+1][k];
    	if(a[x]<a[y])return x;else return y;
    }
    int queryg(int l,int r)
    {
    	int k=lg[r-l+1],x=g[l][k],y=g[r-(1<<k)+1][k];
    	if(b[x]<b[y])return x;else return y;
    }
    bool solve(int l,int r)
    {
    	if(l>=r)return true;
    	int x=queryf(l,r);
    	int y=queryg(l,r);
    	if(x!=y)return false;
    	if(!solve(l,x-1))return false;
    	if(!solve(x+1,r))return false;
    	return true;
    }
    int n;
    void work()
    {
    	for(int i=1;i<=n;i++)a[i]=read(),f[i][0]=i;
    	for(int i=1;i<=n;i++)b[i]=read(),g[i][0]=i;
    	
    	for(int i=1;i<=n;i++)lg[i]=lg[i-1]+(1<<(lg[i-1]+1)==i);
    	
    	for(int k=1;(1<<k)<=n;k++)
    	for(int i=1;i+(1<<k)-1<=n;i++)
    	{
    		int x,y;
    		x=f[i][k-1],y=f[i+(1<<(k-1))][k-1];
    		if(a[x]<a[y])f[i][k]=x;else f[i][k]=y;
    		
    		x=g[i][k-1],y=g[i+(1<<(k-1))][k-1];
    		if(b[x]<b[y])g[i][k]=x;else g[i][k]=y;
    	}
    	int l=1,r=n;
    	while(l<r)
    	{
    		int mid=((l+r)>>1)+1;
    		if(solve(1,mid))l=mid;
    		else r=mid-1;
    	}
    	write(l);putchar('
    ');
    }
    int main()
    {
    	while(~scanf("%d",&n))work();
    	return 0;
    }
    
  • 相关阅读:
    模块之datetime
    模块之time模块
    模块之相对路径导入
    模块之包跨模块导入
    模块
    迭代器
    leetcode234 回文链表(Easy,不简单)
    leetcode543 二叉树的直径(Easy 不简单)
    leetcode538 把二叉树转换为累加树(Easy,不简单)
    leetcode136 只出现一次的数字(Easy)
  • 原文地址:https://www.cnblogs.com/Creed-qwq/p/13961662.html
Copyright © 2011-2022 走看看