UVALive 7148 LRIP【树分治+线段树】

  题意就是要求一棵树上的最长不下降序列,同时不下降序列的最小值与最大值不超过D。

  做法是树分治+线段树,假设树根是x,y是其当前需要处理的子树,对于子树y,需要处理出两个数组MN,MX,MN[i]表示以x为第一个数字的不下降子序列中第i个数的最小值,MX[i]表示以x为第一个数字的不上升子序列中第i个数的最大值。如果当前子树有一个以x为首的不下降序列,那么我们就需要在之前处理的子树中找一条以x为首的满足约束条件不上升序列,可以用线段树来查询。同时每做完一颗子树的时候,用MN,MX对线段树进行更新。对于不经过x的情况可以递归下去处理。

  代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #define N 1000010
  5 using namespace std;
  6 int dp,p[N],s[N],pre[N],tt[N],flag[N],father[N],tmproot,n,d,ttt;
  7 int i,v[N],a,b,mn,mx,MN[N],MX[N],U,V,ans;
  8 int l[N],r[N],smn[N],smx[N],vsmn[N],vsmx[N];
  9 void build(int x,int a,int b)
 10 {
 11     int m;
 12     l[x]=a;r[x]=b;
 13     if (x>ttt) ttt=x;
 14     if (b-a>1)
 15     {
 16         m=(a+b)>>1;
 17         build(2*x,a,m);
 18         build(2*x+1,m,b);
 19     }
 20 }
 21 void clean(int x)
 22 {
 23     if (vsmn[x])
 24     {
 25         smn[x]=0;
 26         if (2*x<=ttt)
 27         vsmn[2*x]=1;
 28         if (2*x+1<=ttt)
 29         vsmn[2*x+1]=1;
 30         vsmn[x]=0;
 31     }
 32     
 33     if (vsmx[x])
 34     {
 35         smx[x]=0;
 36         if (2*x<=ttt)
 37         vsmx[2*x]=1;
 38         if (2*x+1<=ttt)
 39         vsmx[2*x+1]=1;
 40         vsmx[x]=0;
 41     }
 42 }
 43 void change(int x,int a,int b,int c,int typ)
 44 {
 45     int m;
 46     clean(x);
 47     if ((a<=l[x])&&(r[x]<=b))
 48     {
 49         if (typ==0)
 50         smn[x]=max(smn[x],c);
 51         else
 52         smx[x]=max(smx[x],c);
 53         return;
 54     }
 55     m=(l[x]+r[x])>>1;
 56     if (a<m) change(2*x,a,b,c,typ);
 57     if (m<b) change(2*x+1,a,b,c,typ);
 58     clean(2*x);clean(2*x+1);
 59     if (!typ)
 60     smn[x]=max(smn[2*x],smn[2*x+1]);
 61     else
 62     smx[x]=max(smx[2*x],smx[2*x+1]);
 63 }
 64 int query(int x,int a,int b,int typ)
 65 {
 66     int m,ans=0;
 67     clean(x);
 68     if ((a<=l[x]&&(r[x]<=b)))
 69     {
 70         if (typ==0)
 71         return smn[x];
 72         else
 73         return smx[x];
 74     }
 75     m=(l[x]+r[x])>>1;
 76     if (a<m) ans=max(ans,query(2*x,a,b,typ));
 77     if (m<b) ans=max(ans,query(2*x+1,a,b,typ));
 78     return ans;
 79 } 
 80 void link(int x,int y)
 81 {
 82     dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;
 83 }
 84 int getroot(int x,int fa,int sum)
 85 {
 86     int i,f=0;
 87     i=p[x];
 88     father[x]=fa;
 89     s[x]=1;
 90     while (i)
 91     {
 92         if ((tt[i]!=fa)&&(!flag[tt[i]]))
 93         {
 94             getroot(tt[i],x,sum);
 95             s[x]=s[x]+s[tt[i]];
 96             if (s[tt[i]]>sum/2) f=1;
 97         }
 98         i=pre[i];
 99     }
100     if (sum-s[x]>sum/2) f=1;
101     if (!f) tmproot=x;
102 }
103 void dfs(int x,int fa,int mn,int mx)
104 {
105     int i;
106     i=p[x];
107     if (v[x]>=v[fa])
108     {
109         if (mn) 
110         {
111             mn++;
112             MN[mn]=min(MN[mn],v[x]);
113         }
114         if (v[x]>v[fa])
115         mx=0;
116     }
117     if (v[x]<=v[fa])
118     {
119         if (mx) 
120         {
121             mx++;
122             MX[mx]=max(MX[mx],v[x]);
123         }
124         if (v[x]<v[fa])
125         mn=0;
126     }
127     U=max(U,mn);
128     V=max(V,mx);
129     while (i)
130     {
131         if ((tt[i]!=fa)&&(!flag[tt[i]]))
132             dfs(tt[i],x,mn,mx);
133         i=pre[i];
134     }
135 }
136 void work(int x,int sum)
137 {
138     int i,j,k,root;
139     getroot(x,0,sum);
140     root=tmproot;
141     i=p[root];
142     flag[root]=1;
143     while (i)
144     {
145         if (flag[tt[i]]==0)
146         {
147             if (tt[i]==father[root])
148             work(tt[i],sum-s[root]);
149             else
150             work(tt[i],s[tt[i]]);
151         }
152         i=pre[i];
153     }
154 //------------------------------
155     i=p[root];
156     vsmn[1]=1;
157     vsmx[1]=1;
158     while (i)
159     {
160         if (!flag[tt[i]])
161         {
162             for (j=2;j<=U;j++)
163             MN[j]=0x37373737;
164             for (j=2;j<=V;j++)
165             MX[j]=0;
166             U=0;V=0;
167             dfs(tt[i],root,1,1);
168             for (j=2;j<=U;j++)
169             {    
170                 if (MN[j]-d<=v[root])
171                 ans=max(ans,j);
172                 k=MN[j]-d;
173                 if (k<1) k=1;
174                 if (k<=v[root])
175                 ans=max(ans,j+query(1,k-1,v[root],1)-1);
176             }
177             for (j=2;j<=V;j++)
178             {
179                 if (MX[j]+d>=v[root])
180                 ans=max(ans,j);
181                 k=MX[j]+d;
182                 if (k>100000) k=100000;
183                 if (k>=v[root])
184                 ans=max(ans,j+query(1,v[root]-1,k,0)-1);
185             }
186             
187             
188             for (j=2;j<=U;j++)
189             change(1,MN[j]-1,MN[j],j,0);
190             for (j=2;j<=V;j++)
191             change(1,MX[j]-1,MX[j],j,1);
192         }
193         i=pre[i];
194     }
195     flag[root]=0;
196 }
197 int main()
198 {
199     build(1,0,100000);
200     for (i=0;i<=100000;i++)
201     MN[i]=0x37373737;
202     int test,ii=0;
203     scanf("%d",&test);
204     while (test)
205     {
206     test--;
207     ii++;
208     dp=0;memset(p,0,sizeof(p));
209     scanf("%d%d",&n,&d);
210     for (i=1;i<=n;i++)
211     scanf("%d",&v[i]);
212     for (i=1;i<=n-1;i++)
213     {
214         scanf("%d%d",&a,&b);
215         link(a,b);
216         link(b,a);
217     }
218     ans=1;
219     work(1,n);
220     printf("Case #%d: %d\n",ii,ans);
221     }
222 }

 

转载于:https://www.cnblogs.com/fzmh/p/4528415.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
校园失物招领系统管理系统按照操作主体分为管理员和用户。管理员的功能包括字典管理、论坛管理、公告信息管理、失物招领管理、失物认领管理、寻物启示管理、寻物认领管理、用户管理、管理员管理。用户的功能等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 校园失物招领系统管理系统可以提高校园失物招领系统信息管理问题的解决效率,优化校园失物招领系统信息处理流程,保证校园失物招领系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 ,管理员权限操作的功能包括管理公告,管理校园失物招领系统信息,包括失物招领管理,培训管理,寻物启事管理,薪资管理等,可以管理公告。 失物招领管理界面,管理员在失物招领管理界面中可以对界面中显示,可以对失物招领信息的失物招领状态进行查看,可以添加新的失物招领信息等。寻物启事管理界面,管理员在寻物启事管理界面中查看寻物启事种类信息,寻物启事描述信息,新增寻物启事信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值