标签:
[题意]:
给一个排列加上表示循环的括号,问如何让1到n的对应的字典序最大.
从1开始贪心每个数字可以往三个地方走,右边第一个,跳转到左边的某一个,和自己构成循环
对于走到右边第一个的情况,只要判断右边的那个有没有被占据就可以了,如果可以和右边的互换,那么需要在线段树中将右边的数置为0
跳转到左边的某一个,一个数如果跳转到左边的某一个则说明左边的那个是括号开头这个数是括号结尾,用一个线段树查询区间里的最大值,由于括号间是不能重叠的,所以需要用树状数组二分一下左边界.如果这个数是要跳转到左边的某个数,则要对右括号的位置在树状数组里+1,表示这里已经有一个完整的括号了
对于2 1 3 这种情况(2)(1 3)的话得到的字典序最大,所以一个数有时候也是可以跳转到自己的
2 6 1 4 5 6 3 2 2 1 2
4 6 2 5 1 3 2 1
/* ***********************************************
Author :CKboss
Created Time :2015年08月03日 星期一 15时51分35秒
File Name :HDOJ5338.cpp
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
const int maxn=100100;
int n;
int nb[maxn],wz[maxn];
int sed[maxn<<2];
int mx[maxn<<2];
#define lrt rt<<1
#define rrt rt<<1|1
#define lson l,m,lrt
#define rson m+1,r,rrt
void push_up(int rt)
{
mx[rt]=max(mx[lrt],mx[rrt]);
}
void push_down(int rt)
{
if(sed[rt])
{
mx[rrt]=mx[lrt]=0;
sed[rrt]=sed[lrt]=0;
sed[rt]=0;
}
}
void build(int l,int r,int rt)
{
sed[rt]=mx[rt]=0;
if(l==r)
{
mx[rt]=nb[l];
return ;
}
int m=(l+r)/2;
build(lson); build(rson);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R) return mx[rt];
push_down(rt);
int m=(l+r)/2;
int ret=0;
if(L<=m) ret=max(ret,query(L,R,lson));
if(R>m) ret=max(ret,query(L,R,rson));
return ret;
}
void update(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
sed[rt]=1;
mx[rt]=0;
return ;
}
push_down(rt);
int m=(l+r)/2;
if(L<=m) update(L,R,lson);
if(R>m) update(L,R,rson);
push_up(rt);
}
void show(int l,int r,int rt)
{
printf("%d: %d <----> %d mx: %d\n",rt,l,r,mx[rt]);
if(l==r) return;
int m=(l+r)/2;
show(lson); show(rson);
}
int ans[maxn];
bool used[maxn];
int tree[maxn];
inline int lowbit(int x) { return x&(-x); }
void add(int p,int v=1)
{
for(int i=p;i<maxn;i+=lowbit(i))
tree[i]+=v;
}
int sum(int p)
{
int ret=0;
for(int i=p;i;i-=lowbit(i))
ret+=tree[i];
return ret;
}
int get_left(int x)
{
int low=0,high=x-1;
int ans=1,mid;
int bz=sum(x);
if(bz==0) return 0;
while(low<=high)
{
mid=(low+high)/2;
if(sum(mid)<bz)
{
low=mid+1;
}
else
{
ans=mid;
high=mid-1;
}
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T_T;
scanf("%d",&T_T);
while(T_T--)
{
memset(tree,0,sizeof(tree));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",nb+i);
wz[nb[i]]=i;
ans[i]=0; used[i]=0;
}
if(n==1)
{
printf("%d\n",nb[1]); continue;
}
build(1,n,1);
for(int i=1;i<=n;i++)
{
if(ans[i]) continue;
int left=0,right=0,self=0;
/// link to self
if(used[wz[i]]==false) self=i;
/// link to right
if(wz[i]!=n)
{
int pright=wz[i]+1;
if(used[pright]==false)
{
right=nb[pright];
}
}
/// link to left
if(wz[i]!=1)
{
int pleft=get_left(wz[i])+1;
left=query(pleft,wz[i],1,n,1);
}
if(left>self||right>self)
{
if(right>left)
{
ans[i]=right;
used[wz[right]]=true;
update(wz[right],wz[right],1,n,1);
}
else
{
ans[i]=left;
/// link circle
for(int j=wz[left];j<wz[i];j++)
{
ans[nb[j]]=nb[j+1];
used[j]=true;
}
used[wz[i]]=true;
/// set mark
add(wz[i]);
}
}
else
{
ans[i]=self;
used[wz[i]]=true;
add(wz[i]);
}
}
for(int i=1;i<=n;i++)
printf("%d%c",ans[i],(i==n)?10:32);
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDOJ 5338 ZZX and Permutations 线段树+树状数组
标签:
原文地址:http://blog.csdn.net/ck_boss/article/details/47263773