hdu 3564 线段树+dp

实在惭愧。。。理解错了题意还A了。。 

题意:现在第i个数字表示i这个数字放在第几个位置上面,如果这个位置上面已经有数字则向后移动。

一开始我以为是先将所有的数字放好位子之后+二分最长上升就可以,但是思路错了,真正应该记录的值是i这个数字存放在哪个位子,我们在保证数字一定上升的基础上,来求位子的上升。因为第一个数字放的是1,第二个为2,这样的话我们就能求出每次放一个数字产生的最上升序列长度了。。

View Code
 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 const int N = 100005;
 5 int Pos[N],num[N],len[N<<2];
 6 void build(int t,int l,int r)
 7 {
 8      len[t]=r-l+1;
 9      if(l==r)return ;
10      int m=(l+r)>>1;
11      build(t<<1,l,m);
12      build(t<<1|1,m+1,r);
13 }
14 void update(int t,int l,int r,int v,int i)
15 {
16      len[t]--;
17      if(l==r)
18      {
19          Pos[i]=l;
20          return ;
21      }
22      int m=(r+l)>>1;
23      if(len[t<<1]>=v)update(t<<1,l,m,v,i);
24      else update(t<<1|1,m+1,r,v-len[t<<1],i);
25 }
26 int F_pos(int k,int len)
27 {
28     int l=1,r=len;
29     while(l<=r)
30     {
31         int m=(l+r)>>1;
32         if(num[m]<k)l=m+1;
33         else r=m-1;
34     }
35     return l;
36 }
37 int main()
38 {
39     int t,n,top,T=0;
40     scanf("%d",&t);
41     while(t--)
42     {
43           scanf("%d",&n);
44           build(1,1,n);
45           for(int i=1;i<=n;i++)
46           {
47               scanf("%d",&num[i]);
48               num[i]++;
49           };
50           for(int i=n;i>=1;i--)
51           {
52              update(1,1,n,num[i],i);
53           }
54           top=0;
55           printf("Case #%d:\n",++T);
56           for(int i=1;i<=n;i++)
57           {
58              if(top==0||Pos[i]>num[top])
59              num[++top]=Pos[i];
60              else
61              {
62                int f=F_pos(Pos[i],top);
63                num[f]=Pos[i];
64              }
65              printf("%d\n",top);
66           }
67           printf("\n");
68     }
69     return 0;
70 }

 

posted @ 2012-10-31 20:38  诺小J  阅读(286)  评论(0编辑  收藏  举报