[点分治] LA 7148 LRIP

来源:互联网 发布:网络女主播招聘 编辑:程序博客网 时间:2024/06/06 06:39

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

点分 记录经过重心结尾是多少的不降/不升的长度 然后用set维护一个单调的东西来查询 也可以用线段树维护


#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#include<set>#define cl(x) memset(x,0,sizeof(x))using namespace std;typedef pair<int,int> abcd;inline char nc(){static char buf[100000],*p1=buf,*p2=buf;if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }return *p1++;}inline void read(int &x){char c=nc(),b=1;for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;}const int oo=1<<30;const int N=100005;struct edge{int u,v,next;}G[N<<1];int head[N],inum;inline void add(int u,int v,int p){G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;}int n,D,ans;int val[N];int size[N],del[N];int minimum,rt,sum;#define V G[p].vinline void Root(int u,int fa){size[u]=1; int maximum=0;for (int p=head[u];p;p=G[p].next)if (V!=fa && !del[V])Root(V,u),size[u]+=size[V],maximum=max(maximum,size[V]);maximum=max(maximum,sum-size[u]);if (maximum<minimum) minimum=maximum,rt=u;}int len,c[N]; set<abcd> Set1,Set2;typedef set<abcd>::iterator ITER;inline void dfs1(int u,int fa){if (val[u]>=c[len]) c[++len]=val[u]; else return;abcd tem=abcd(val[u],len);ITER it=Set2.lower_bound(abcd(val[u]-D,0));if (it!=Set2.end()){ans=max(ans,len+it->second-1);}for (int p=head[u];p;p=G[p].next)if (V!=fa && !del[V])dfs1(V,u);len--;}inline void update1(int u,int fa){if (val[u]>=c[len]) c[++len]=val[u]; else return;ITER it=(Set1.insert(abcd(val[u],len))).first,tem;int flag=0;if (it!=Set1.begin()){tem=it; tem--;if (tem->second>it->second) Set1.erase(it),flag=1;}while (!flag){tem=it; tem++; if (tem==Set1.end()) break;if (tem->second<it->second) Set1.erase(tem);else break; }for (int p=head[u];p;p=G[p].next)if (V!=fa && !del[V])update1(V,u);len--;}inline void dfs2(int u,int fa){if (val[u]<=c[len]) c[++len]=val[u]; else return;abcd tem=abcd(val[u],len);//for (ITER it=Set1.begin();it!=Set1.end();it++)//printf("%d %d\n",it->first,it->second);ITER it=Set1.upper_bound(abcd(val[u]+D,1<<30));if (it!=Set1.begin()){it--; //printf("%d %d\n",it->first,it->second);ans=max(ans,len+it->second-1);}for (int p=head[u];p;p=G[p].next)if (V!=fa && !del[V])dfs2(V,u);len--;}inline void update2(int u,int fa){if (val[u]<=c[len]) c[++len]=val[u]; else return;ITER it=(Set2.insert(abcd(val[u],len))).first,tem;int flag=0;tem=it; tem++;if (tem!=Set2.end() && tem->second>it->second)Set2.erase(it),flag=1; while (!flag && it!=Set2.begin()){tem=it; tem--;if (tem->second<it->second) Set2.erase(tem);else break; }for (int p=head[u];p;p=G[p].next)if (V!=fa && !del[V])update2(V,u);len--;}inline void Solve(int u){del[u]=1;Set1.clear(); Set2.clear(); Set1.insert(abcd(val[u],1));Set2.insert(abcd(val[u],1));for (int p=head[u];p;p=G[p].next)if (!del[V]){c[len=1]=val[u]; dfs1(V,u);c[len=1]=val[u]; dfs2(V,u);c[len=1]=val[u]; update1(V,u);c[len=1]=val[u]; update2(V,u);}for (int p=head[u];p;p=G[p].next)if (!del[V]){minimum=n+1; sum=size[V]; Root(V,u);Solve(rt);}}int main(){int T; int iu,iv;freopen("t.in","r",stdin);freopen("t.out","w",stdout);read(T);for (int _t=1;_t<=T;_t++){read(n); read(D);for (int i=1;i<=n;i++) read(val[i]);for (int i=1;i<n;i++)read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);ans=1;sum=n; minimum=n+1; Root(1,0);Solve(rt); printf("Case #%d: %d\n",_t,ans);cl(head); inum=0;cl(del);}return 0;}


0 0