Boring Class
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 798 Accepted Submission(s): 210
Problem Description
Mr. Zstu and Mr. Hdu are taking a boring class , Mr. Zstu comes up with a problem to kill time, Mr. Hdu thinks it’s too easy, he solved it very quickly, what about you guys?
Here is the problem:
Give you two sequences L1,L2,...,Ln and R1,R2,...,Rn .
Your task is to find a longest subsequence v1,v2,...vm satisfies
v1≥1 , vm≤n , vi<vi+1 .(for i from 1 to m - 1)
Lvi≥Lvi+1 , Rvi≤Rvi+1 (for i from 1 to m - 1)
If there are many longest subsequence satisfy the condition, output the sequence which has the smallest lexicographic order.
Here is the problem:
Give you two sequences L1,L2,...,Ln and R1,R2,...,Rn .
Your task is to find a longest subsequence v1,v2,...vm satisfies
v1≥1 , vm≤n , vi<vi+1 .(for i from 1 to m - 1)
Lvi≥Lvi+1 , Rvi≤Rvi+1 (for i from 1 to m - 1)
If there are many longest subsequence satisfy the condition, output the sequence which has the smallest lexicographic order.
![](http://acm.hdu.edu.cn/data/images/5324-1.jpg)
Input
There are several test cases, each test case begins with an integer n.
1≤n≤50000
Both of the following two lines contain n integers describe the two sequences.
1≤Li,Ri≤109
1≤n≤50000
Both of the following two lines contain n integers describe the two sequences.
1≤Li,Ri≤109
Output
For each test case ,output the an integer m indicates the length of the longest subsequence as described.
Output m integers in the next line.
Output m integers in the next line.
Sample Input
5 5 4 3 2 1 6 7 8 9 10 2 1 2 3 4
Sample Output
5 1 2 3 4 5 1 1
强大的树套树!!!!
题意是A数组递增,B数组递减的LCS
用树状数组维护A数组的有序性,然后在树状数组的每个节点都挂一棵Treap就行。
总结:
这题在做的时候写的很慢,参照网上的大神的代码还是不知道怎么下手,也许是因为这是我写的第一个树套树代码吧,总之写了好久。在写的过程中,我发现了好多问题,还是要提一提。
1、在写Treap时我一直用的是指针,一直没注意分配的空间,导致MLE了好几发,后来才知道,指针的空间可以事先申请好,也就是开个数组,那样就不用担心已分配的内存无法释放了。
2、对于B数组的实现,我是没有注意太多的,以至于写完后发现写反了,好在这题可以用-B扑救
3、对于Treap的更新操作有好多都不及时,导致出现错误
4、对于答案相同的状态,实现并没有考虑明白
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 50005
int n;
int id[maxn];
struct Point
{
int x,y,z;
bool operator<(Point const &a)const{return y==a.y?x<a.x:y<a.y;}
}a[maxn];
bool cmp(Point a,Point b){return a.x<b.x;}
struct Node{
//Treap信息
Node *son[2];
int rank;
//节点信息
int key;//z轴
int id,len;
//最佳信息
int bid,blen;
bool operator<(const Node &a)const{return rank<a.rank;}
int cmp(int x)const{if(x==key)return -1;return x<=key?0:1;}
void maintain()//更新节点的最佳信息
{
blen = len,bid = id;
if(blen<son[0]->blen)blen = son[0]->blen,bid = son[0]->bid;
if(blen<son[1]->blen)blen = son[1]->blen,bid = son[1]->bid;
}
void initial()
{
rank =key=id=len=bid=blen = 0;
}
};
Node *null = new Node();
struct Treap{
Node node[maxn*30];
int cntnode;
void initial(){cntnode = 0;}
Node* newNode()
{
node[++cntnode].initial();
node[cntnode].son[0] = node[cntnode].son[1] = null;
return &node[cntnode];
}
void rotate(Node* &o,int d)
{
Node* k = o->son[d^1];o->son[d^1] = k -> son[d];k->son[d] = o;
o->maintain();k->maintain();o = k;//注意,必须先维护o再维护k,因为o是子节点,不优先维护,会导致父节点出错
}
void ins(Node* &o,int x,int id,int len)//x为键值,p为带插入节点
{
if(o==null)
{
o = newNode();
o->id = id;
o->len = len;
o->rank = rand();
o->bid = o->id;o->blen = o->len;
o->key = x;o->son[0] = o->son[1] = null;
}//将节点添加入平衡树中,当前节点为空时,直接插入
else
{
int d = o->cmp(x);
if(d == -1)
{
if(len > o->len || len == o->len && id < o->id)
{
o->len = len;
o->id = id;
o->maintain();
return;
}
}
ins(o->son[d],x,id,len);
o->maintain();//插入后,需要维护
if(o < o->son[d])
rotate(o,d^1);//当位于左儿子时,需要进行的是右旋,当位于右儿子时应当进行左旋,因此通项为rotate(o,d^1)
}
}
Node search(Node* &o,int v2)
{
//cout<<"Treap::search"<< o->id << endl;
if(o == null)
{
return Node();
}
if(v2 < o->key) return search(o->son[0],v2);
else
{
Node tmp = Node();
tmp.id= o->id;
tmp.len = o->len;
if(o->son[0]->blen>tmp.len || o->son[0]->blen == tmp.len
&& o->son[0]->bid < tmp.id)
{
tmp.len = o->son[0]->blen;
tmp.id = o->son[0]->bid;
}
Node tmp1 = search(o->son[1],v2);
if(tmp1.len>tmp.len||tmp1.len == tmp.len && tmp.id>tmp1.id)
tmp = tmp1;
return tmp;
}
}
}treap;
struct {
Node *fwt[maxn];
int N;
int lowbit(int x) {return x&(-x);}
void initial(int n){N = n;for(int i = 0;i<=n;i++)fwt[i] = null;}
void ins(int v1,int v2,Node p)//插入操作
{
while(v1<=N)
{
//cout<<v1<<endl;
treap.ins(fwt[v1],v2,p.id,p.len);
v1+=lowbit(v1);
}
}
Node search(int v1,int v2)//树状数组查找操作,获得最优转移操作
{
Node ans = Node();
Node tmp;//只需要id和len就行
while(v1!=0)
{
tmp = treap.search(fwt[v1],v2);
//cout<<"BIT::search "<<v1<<","<<tmp.id<<endl;
if(ans.len<tmp.len || ans.len == tmp.len && ans.id>tmp.id) ans = tmp;
v1-=lowbit(v1);
}
ans.len++;//处理好答案再返回结果
return ans;
}
}BIT;
void print(Node ans)
{
printf("%d\n",ans.len);
int t = ans.id;
while(id[t])
{
printf("%d ",t);
t = id[t];
}
printf("%d\n",t);
}
int main()
{
#ifdef ACBang
freopen("1009.in","r",stdin);
freopen("1.out","w",stdout);
#endif // ACBang
while(~scanf("%d",&n))
{
/*------读入加y轴离散化------*/
treap.initial();
for(int i = 1;i<=n;i++){a[i].x= i;scanf("%d",&a[i].y);}
for(int i = 1;i<=n;i++){scanf("%d",&a[i].z);a[i].z = -a[i].z;}
sort(a+1,a+n+1);
int m = 0;id[1] = ++m;
for(int i = 2;i<=n;i++)if(a[i].y == a[i-1].y) id[i] = m;else id[i]=++m;
for(int i=1;i<=n;i++)a[i].y = id[i];
sort(a+1,a+n+1,cmp);
BIT.initial(m+1);
/*---------------------------------*/
Node ans = Node();//保存最后结果
Node tmp;
for(int i = n;i>=1;i--)//y轴要满足逆序,所以倒着做
{
//cout<<"do i"<<endl;
tmp = BIT.search(a[i].y,a[i].z);
// cout<<"The answer of "<<i<<" is "<<tmp.id<<" "<<treap.cntnode<<endl;
id[i] = tmp.id;
tmp.id = i;
tmp.key = a[i].z;
if(ans.len<=tmp.len) ans = tmp;
BIT.ins(a[i].y,a[i].z,tmp);
}
print(ans);
}
return 0;
}