一道题

n<=100000个<=100000的正数,其中有一些0表示这个位置的数字可以是L~R中的一个,L,R是给定常数且1<=L<=R<=100000,问最长上升子序列。

先暴力啊!$f(i,j)$表示前i个数中以j结尾的答案。$f(i,j)=f(i-1,j)$,$f(i,a_i)=max(f(i-1,j)+1),j<a_i$为$a_i$>0的转移方式,而$f(i,j)=max(f(i-1,k)+1),L<=j<=R,k<=j$为$a_i=0$的转移方式。

不如$f(i,j)$表示前i个数中以$<=j$的结尾的答案,一来是这样表示是一个单调序列,二来转移简洁了些:$f(i,j)=f(i-1,j)$,$f(i,a_i~R)>?=f(i-1,a_i-1),j<a_i$,$f(i,j)=f(i-1,j-1)+1,L<=j<=R$,诸如此类,细节略。

这些操作,在从i-1变成i时可以用一个平衡树维护。需要区间加,区间赋值,单点查询。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 #include<stdlib.h>
  5 #include<math.h>
  6 //#include<time.h>
  7 //#include<iostream>
  8 using namespace std;
  9 
 10 int n,L,R,m=100001;
 11 #define maxn 100011
 12 int a[maxn];
 13 
 14 inline int max(int x,int y) {return x>y?x:y;}
 15 inline int min(int x,int y) {return x<y?x:y;}
 16 struct Splay
 17 {
 18     struct Node
 19     {
 20         int v,size,Max,Min;
 21         int add,be;
 22         int fa,son[2];
 23     }a[maxn<<1];
 24     int size,root,live,die;
 25     Splay() {size=root=0;}
 26     inline void besingle(int x,int v)
 27     {
 28         if (!x) return;
 29         a[x].v=v; a[x].Max=a[x].Min=v;
 30         a[x].add=0;
 31         a[x].be=v;
 32     }
 33     inline void addsingle(int x,int v)
 34     {
 35         if (!x) return;
 36         a[x].v+=v; a[x].Max+=v; a[x].Min+=v;
 37         if (a[x].be) a[x].be+=v;
 38         else a[x].add+=v;
 39     }
 40     inline void down(int x)
 41     {
 42         const int &p=a[x].son[0],&q=a[x].son[1];
 43         if (a[x].add) addsingle(p,a[x].add),addsingle(q,a[x].add),a[x].add=0;
 44         if (a[x].be) besingle(p,a[x].be),besingle(q,a[x].be),a[x].be=0;
 45     }
 46     inline void up(int x)
 47     {
 48         if (!x || x==live || x==die) return;
 49         const int &p=a[x].son[0],&q=a[x].son[1];
 50         a[x].size=a[p].size+a[q].size+1;
 51         a[x].Max=max(a[p].Max,max(a[q].Max,a[x].v));
 52         a[x].Min=min(a[p].Min,min(a[q].Min,a[x].v));
 53     }
 54     int sta[maxn<<1],top;
 55     inline void download(int x)
 56     {
 57         top=0; for (int i=x;i;i=a[i].fa) sta[++top]=i;
 58         while (top) down(sta[top--]);
 59     }
 60     inline void rotate(int x)
 61     {
 62         const int y=a[x].fa,z=a[y].fa;
 63         bool w=(x==a[y].son[0]);
 64         a[x].fa=z;
 65         if (z) a[z].son[y==a[z].son[1]]=x;
 66         a[y].son[w^1]=a[x].son[w];
 67         if (a[x].son[w]) a[a[x].son[w]].fa=y;
 68         a[x].son[w]=y;
 69         a[y].fa=x;
 70         up(y); up(z);
 71     }
 72     inline void splay(int x,int top)
 73     {
 74         download(x);
 75         while (a[x].fa!=top)
 76         {
 77             const int y=a[x].fa,z=a[y].fa;
 78             if (z!=top)
 79             {
 80                 if ((x==a[y].son[0])^(y==a[z].son[0])) rotate(x);
 81                 else rotate(y);
 82             }
 83             rotate(x);
 84         }
 85         up(x);
 86         if (!top) root=x;
 87     }
 88     inline void build(int &x,int L,int R)
 89     {
 90         if (L>R) {x=0;return;}
 91         x=++size;
 92         a[x].v=a[x].add=a[x].be=0;
 93         if (L==R)
 94         {
 95             a[x].son[0]=a[x].son[1]=0; a[x].size=1; a[x].Max=a[x].Min=0;
 96             if (L==0) live=x; if (L==m+1) die=x; return;
 97         }
 98         const int mid=(L+R)>>1;
 99         if (mid==0) live=x; if (mid==m+1) die=x;
100         build(a[x].son[0],L,mid-1);
101         if (a[x].son[0]) a[a[x].son[0]].fa=x;
102         build(a[x].son[1],mid+1,R);
103         if (a[x].son[1]) a[a[x].son[1]].fa=x;
104         up(x);
105     }
106     inline void build()
107     {
108         a[root].fa=0; build(root,0,m+1); 
109         a[live].Max=a[die].Max=-0x3f3f3f3f;
110         a[live].Min=a[die].Min=0x3f3f3f3f;
111     }
112     int find(int v)
113     {
114         int x=root,ans=0;
115         while (x)
116         {
117             if (a[a[x].son[0]].size<v) ans=x,v-=a[x].size-a[a[x].son[1]].size,x=a[x].son[1];
118             else x=a[x].son[0];
119         }
120         if (ans) splay(ans,0);
121         return ans;
122     }
123     int getv(int id) {return a[find(id)].v;}
124     inline void join(int x,int y)
125     {
126         a[x].fa=a[y].fa=0;
127         if (x*y==0) {root=x+y; return;}
128         int z=x;
129         while (a[z].son[1]) z=a[z].son[1];
130         splay(z,0);
131         a[z].son[1]=y; a[y].fa=z; up(z);
132     }
133     inline void Delete(int id)
134     {
135         int x=find(id);
136         join(a[x].son[0],a[x].son[1]);
137     }
138     inline void copy(int id)
139     {
140         int x=find(id),y=a[x].son[1];
141         while (a[y].son[0]) y=a[y].son[0];
142         splay(y,x);
143         int z=++size;
144         a[z].son[0]=a[z].son[1]=0; a[z].v=a[x].Max=a[x].Min=a[x].v; a[z].size=1; a[z].add=a[z].be=0;
145         a[z].fa=y; a[y].son[0]=z; up(y); up(x);
146     }
147     inline int add(int L,int R,int v)
148     {
149         L--; R++;
150         int y=find(R),x=find(L);
151         splay(y,x); int z=a[y].son[0];
152         addsingle(z,v);
153         up(y); up(x);
154         return a[z].Max;
155     }
156     inline void modmax(int L,int R,int v)
157     {
158         L--; R++;
159         int y=find(R),x=find(L);
160         splay(y,x); int z=a[y].son[0];
161         while (1)
162         {
163             down(z);
164             if (a[z].Min>=v) break;
165             if (a[z].Max<=v) {besingle(z,v); break;}
166             a[z].v=max(a[z].v,v);
167             if (!a[z].son[0] && !a[z].son[1]) break;
168             if (!a[z].son[0] || !a[z].son[1]) z=a[z].son[0]+a[z].son[1];
169             else if (a[a[z].son[0]].Max<=v) besingle(a[z].son[0],v),z=a[z].son[1];
170             else z=a[z].son[0];
171         }
172         while (z) {up(z); z=a[z].fa;}
173     }
174     int ans;
175     inline void dfs(int x)
176     {
177         ans=max(ans,a[x].v);
178         down(x);
179         if (a[x].son[0]) dfs(a[x].son[0]);
180         if (a[x].son[1]) dfs(a[x].son[1]);
181     }
182     int getans()
183     {
184         ans=0;
185         dfs(root);
186         return ans;
187     }
188 }t;
189 
190 int qread()
191 {
192     char c;int s=0; while (!((c=getchar())>='0' && c<='9'));
193     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s;
194 }
195 int main()
196 {
197 //    freopen("orzzsn.in","r",stdin);
198 //    freopen("orzzsn.out","w",stdout);
199     scanf("%d%d%d",&n,&L,&R);
200     for (int i=1;i<=n;i++) a[i]=qread();
201     
202     t.build();
203     for (int i=1;i<=n;i++)
204     {
205         if (a[i]) t.modmax(a[i]+1,m+1,t.getv(a[i])+1);
206         else
207         {
208             t.Delete(R+1);
209             t.copy(L);
210             t.modmax(R+2,m+1,t.add(L+1,R+1,1));
211         }
212     }
213     printf("%d\n",t.getans());
214     return 0;
215 }
View Code

然而不用这样。 维护这个序列的差分即可。假如当前要更新$[L,R]$,那就在L这里插入一个+1标记,在R右边删掉最左的一个差分标记即可,就包含了区间加和区间取Max的操作。

posted @ 2017-12-21 16:45  Blue233333  阅读(217)  评论(0编辑  收藏  举报