[樹形DP 雙指標掃描] 2016 計蒜之道 初賽 第六場 微軟的員工福利
阿新 • • 發佈:2019-02-04
n3的做法可以對每個點列舉最小值最大值
我們發現極差/1000最多隻有101種取值
那我們列舉極差 列舉最大值 同時順便維護在這個取值區間內的最優決策
較大提升的顯示器不在區間內的話,就一定要把較小顯示器選上;如果來自同一子樹的兩個顯示器都在區間內,貪心選 dpdp 值較大的那個
可以用尺取法雙指標掃過
複雜度(101n+nlogn)
log的複雜度來自排序
#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; typedef long long ll; 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 N=200005; 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 a[N][2]; ll f[N][2]; struct abcd{ int key,u,c; abcd(int key=0,int u=0,int c=0):key(key),u(u),c(c) { } bool operator < (const abcd &B) const{ return key==B.key?(u==B.u?c<B.c:u<B.u):key<B.key; } }tmp[N<<1],lst[N<<1]; int pnt; int n; int vst[N][2]; ll ret=0,cur,num,tot; const ll inf=1LL<<45; inline ll calc(int u){ if (vst[u][1] && vst[u][0]) return max(f[u][1],f[u][0]); if (vst[u][0]) return f[u][0]; if (vst[u][1]) return f[u][1]; return 0; } inline void change(int u,int c,int r){ if (r==1){ cur-=calc(u); num-=vst[u][0]|vst[u][1]; vst[u][c]=1; cur+=calc(u); num+=vst[u][0]|vst[u][1]; }else{ cur-=calc(u); num-=vst[u][0]|vst[u][1]; vst[u][c]=0; cur+=calc(u); num+=vst[u][0]|vst[u][1]; } ret=(num==tot)?cur:-1LL<<60; } #define C(x,y) (((x)-(y)+999)/1000) #define V G[p].v inline void dfs(int u,int fa){ for (int p=head[u];p;p=G[p].next) if (V!=fa) dfs(V,u); pnt=0; f[u][0]=a[u][0]; f[u][1]=a[u][1]; for (int p=head[u];p;p=G[p].next) if (V!=fa){ tmp[++pnt]=abcd(a[V][0],V,0); tmp[++pnt]=abcd(a[V][1],V,1); } ll Ans[2]; for (int c=0;c<2;c++){ Ans[c]=-1LL<<60; for (int i=1;i<=pnt;i++) lst[i]=tmp[i]; lst[++pnt]=abcd(a[u][c],u,c); sort(lst+1,lst+pnt+1); int pos=lower_bound(lst+1,lst+pnt+1,abcd(a[u][c],u,c))-lst; for (int x=0;x<=C(lst[pnt].key,lst[1].key);x++){ cur=0; tot=0; vst[u][0]=vst[u][1]=0; tot++; for (int p=head[u];p;p=G[p].next) if (V!=fa) vst[V][0]=vst[V][1]=0,tot++; int iter=pos; num=0; change(lst[iter].u,lst[iter].c,1); while (iter-1>=1 && C(lst[pos].key,lst[iter-1].key)<=x){ iter--; change(lst[iter].u,lst[iter].c,1); } Ans[c]=max(Ans[c],ret-(ll)C(lst[pos].key,lst[iter].key)*666*u); for (int i=pos+1;i<=pnt;i++){ change(lst[i].u,lst[i].c,1); while (C(lst[i].key,lst[iter].key)>x){ change(lst[iter].u,lst[iter].c,-1); iter++; } Ans[c]=max(Ans[c],ret-(ll)C(lst[i].key,lst[iter].key)*666*u); } } pnt--; } f[u][0]=Ans[0]; f[u][1]=Ans[1]; } int main(){ int iu,iv; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); for (int i=1;i<=n;i++) for (int j=0;j<2;j++) read(a[i][j]); for (int i=1;i<n;i++){ read(iu); read(iv); add(iu,iv,++inum); add(iv,iu,++inum); } dfs(1,0); printf("%lld\n",max(f[1][0],f[1][1])); return 0; }