一些约定:不管是队列、数组,还是栈,都从1号开始 存放数据
因此队列初始化就设 head=1,tail=0,栈初始化设top=0,++top后存数
习题练习
https://www.cnblogs.com/reverymoon/p/9525764.html
https://www.cnblogs.com/HocRiser/p/10620518.html
笛卡尔树线性建立思路:
利用单调栈线性构造笛卡尔树。单调栈递增则维护最小堆,递减则维护最大堆。以维护最小堆为例。
遍历原序列的每一个节点,然后与栈顶元素比较,如果当前节点小于栈顶节点,则弹出栈顶节点,并把弹出节点设为当前节点的左子树。一直到当前节点大于栈顶节点为止,把当前节点设为栈顶节点的右子树,并把当前节点入栈。
这里都是原序列的索引操作。
int Build(int n)
{
int top=0,stack[maxn];
for(int i=1;i<=n;++i)
{
while(top&&A[stack[top]]>A[i])
CT[i].l=stack[top--];
if(top)
CT[stack[top]].r=i;
stack[++top]=i;
}
return stack[1];
}
笛卡尔树递归构造O(n2):
每次选取区间最大值作为根,然后往两边递归也可以建树。直接暴力是O(n2)的,线段树优化一下就可以O(nlogn)
HDU -1506
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=1e9+7;
int A[maxn],n;
ll ans;
struct CartesianTree
{
int l,r;
}CT[maxn];
void Init(int n)
{
for(int i=1;i<=n;++i)
CT[i].l=CT[i].r=0;
}
int Build(int n)
{
int top=0,stack[maxn];
for(int i=1;i<=n;++i)
{
while(top&&A[stack[top]]>A[i])
CT[i].l=stack[top--];
if(top)
CT[stack[top]].r=i;
stack[++top]=i;
}
return stack[1];
}
int dfs(int root)
{
if(root==0)
return 0;
ll cnt=dfs(CT[root].l)+dfs(CT[root].r)+1;
ans=max(ans,cnt*A[root]);
return cnt;
}
int main()
{
while(scanf("%d",&n)&&n)
{
Init(n);
rep(i,1,n)
cin>>A[i];
int root=Build(n);
ans=0;
dfs(root);
cout<<ans<<"\n";
}
return 0;
}
POJ - 1785
const int maxn=5e4+5,INF=0x3f3f3f3f;
const int mod=1e9+7;
struct CartesianTree
{
int l,r;
char key[100];
int value;
bool operator<(const CartesianTree &b) const
{
return strcmp(key,b.key)<0;
}
}CT[maxn];
int Build(int n)
{
int top=0,stack[maxn];
for(int i=1;i<=n;++i)
{
while(top&&CT[i].value>CT[stack[top]].value)
CT[i].l=stack[top--];
if(top)
CT[stack[top]].r=i;
stack[++top]=i;
}
return stack[1];
}
void InOrder(int rt)
{
if(rt==0)
return;
printf("(");
InOrder(CT[rt].l);
printf("%s/%d",CT[rt].key,CT[rt].value);
InOrder(CT[rt].r);
printf(")");
}
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
rep(i,1,n)
{
scanf(" %[^/]/%d",&CT[i].key,&CT[i].value);
CT[i].l=CT[i].r=0;
}
sort(CT+1,CT+1+n);
int rt=Build(n);
InOrder(rt);
printf("\n");
}
return 0;
}