[二进制分组 dsu on tree 二次函数] Codechef KILLER Painting Tree
来源:互联网 发布:泛微java怎么样 编辑:程序博客网 时间:2024/05/29 18:55
首先我们可以列一个dp 按深度
我们发现这条链的贡献是一个关于祖先深度二次函数 具体形式我忘了 而其他贡献则是一路上来兄弟子树中的最大值累加
这样就很明确了 是要求对每一个点维护一个二次函数 还要资瓷子树加 查询子树中
首先询问一坨二次函数最大值 有一个经典做法来自 BZOJ2646
我们可以维护
注意这个轮廓是资瓷合并的
但是我们发现这个轮廓是不资瓷插入一条二次函数的 这样的复杂度还是
资瓷插入有什么好呢 我们使用dsu on tree 的技巧 就能够总复杂度
这样子树加就能够很轻易的实现了
常数感人
#include<cstdio>#include<cstdlib>#include<cmath>#include<vector>#include<algorithm>#include<cstring>#include<iostream>#include<iomanip>#define PB push_back#define cl(x) memset(x,0,sizeof(x))using namespace std;typedef long long ll;typedef long double ld;inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*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;}inline void read(ld &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=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;}#define V G[p].vint n;ld H[N],C[N],d[N],h;int size[N],son[N];inline void dfs(int u,int fa){ h=max(h,d[u]); size[u]=1; for (int p=head[u];p;p=G[p].next) if (V!=fa) d[V]=d[u]+1,dfs(V,u),size[u]+=size[V]; int maxv=0; son[u]=0; for (int p=head[u];p;p=G[p].next) if (V!=fa && size[V]>maxv) maxv=size[son[u]=V];}const ld eps=1e-11;const ld oo=1e6;struct Func{ ld a,b,c; Func() { } Func(ld a,ld b,ld c):a(a),b(b),c(c) { } ld f(ld x){ return a*x*x+b*x+c; }}F[N];struct P{ ld l,r; int p; P(){ } P(ld l,ld r,int p):l(l),r(r),p(p) { }};inline ld pos(const Func &a,const Func &b,ld l,ld r){ ld A=a.a-b.a,B=a.b-b.b,C=a.c-b.c; if (fabs(A)<eps){ if (fabs(B)<eps) return r; ld x=-C/B; if (x>l+eps&&x<r) return x; return r; } ld d=B*B-4*A*C; if (d<-eps) return r; d=sqrt(d); ld x=(-B-d)/(2*A),y=(-B+d)/(2*A),ret=r; if (x>l+eps&&x<r) ret=x; if (y>l+eps&&y<r) ret=min(ret,y); return ret;}struct Bin{ vector<Func> e; int tot; vector<ld> q; vector<P> c; void merge(vector<P>&f,const vector<P>&a,const vector<P>&b){ int na=a.size(),nb=b.size(),pa=0,pb=0; c.clear(); q.clear(); q.PB(-oo); while (pa<na && pb<nb) if (a[pa].r<b[pb].r || pb==nb){ if (a[pa].r>q.back()+eps) q.PB(a[pa].r); pa++; }else{ if (b[pb].r>q.back()+eps) q.PB(b[pb].r); pb++; } while (pa<na){ if (a[pa].r>q.back()+eps) q.PB(a[pa].r); pa++; } while (pb<nb){ if (b[pb].r>q.back()+eps) q.PB(b[pb].r); pb++; } for (int i=0,j=0,k=0;k<q.size()-1;k++){ ld l=q[k],r=q[k+1]; while (i<na && a[i].r+eps<r) i++; while (j<nb && b[j].r+eps<r) j++; if (i==na || a[i].l>l+eps){ c.PB(P(l,r,b[j].p)); continue; } if (j==nb || b[j].l>l+eps){ c.PB(P(l,r,a[i].p)); continue; } while (l+eps<r){ ld m=pos(e[a[i].p],e[b[j].p],l,r),mid=(l+m)/2; if (e[a[i].p].f(mid)<e[b[j].p].f(mid)) c.PB(P(l,m,a[i].p)); else c.PB(P(l,m,b[j].p)); l=m; } } for (int i=0,j;i<c.size();i=j){ j=i; while (j<c.size() && c[i].p==c[j].p) j++; f.PB(P(c[i].l,c[j-1].r,c[i].p)); } } ld query(const vector<P>&v,ld o){ int l=0,mid,r=v.size()-1; while (l<=r){ mid=(l+r)>>1; if (v[mid].r+eps<o) l=mid+1; else if (v[mid].l-eps>o) r=mid-1; else return e[v[mid].p].f(o); } } ld tag; vector<P> v[20]; int cnt,size[20]; Bin(){ e.PB(Func()); tot=0; tag=0; cnt=0; } void clear(){ for (int i=1;i<=cnt;i++) v[i].clear(); cnt=0; tot=0; tag=0; e.clear(); e.PB(Func()); } vector<P> tmp; void Add(Func a){ a.c-=tag; e.PB(a); ++tot; ++cnt; size[cnt]=1; v[cnt].PB(P(-oo,oo,tot)); while (cnt>1 && size[cnt]==size[cnt-1]){ tmp.clear(); merge(tmp,v[cnt],v[cnt-1]); v[cnt-1]=tmp; v[cnt].clear(); cnt--; size[cnt]<<=1; } } ld Query(ld x){ ld ans=1e30; for (int i=1;i<=cnt;i++) ans=min(ans,query(v[i],x)); return ans+tag; }}B[N];int bi[N];int bcnt;ld tag[N];ld minv[N];inline void Add(int u,int fa,ld T,Bin &B){ T+=tag[u]; F[u].c+=T; B.Add(F[u]); F[u].c-=T; for (int p=head[u];p;p=G[p].next) if (V!=fa) Add(V,u,T,B);}inline void dp(int u,int fa){ for (int p=head[u];p;p=G[p].next) if (V!=fa) dp(V,u); ld sum=0; for (int p=head[u];p;p=G[p].next) if (V!=fa){ minv[V]=B[bi[V]].Query(d[V]); sum+=minv[V]; } if (son[u]){ bi[u]=bi[son[u]]; B[bi[u]].tag+=sum-minv[son[u]]; tag[son[u]]+=sum-minv[son[u]]; for (int p=head[u];p;p=G[p].next) if (V!=fa && V!=son[u]){ tag[V]+=sum-minv[V]; Add(V,u,0,B[bi[u]]); } }else{ bi[u]=++bcnt; } F[u].a=C[u]/2.0; F[u].b=-C[u]*C[u]-C[u]*h-C[u]/2.0; F[u].c=-C[u]*d[u]*(d[u]+1)/2.0-H[u]+sum+(d[u]+1)*(C[u]*C[u]+C[u]*h); B[bi[u]].Add(F[u]);}int main(){ freopen("t.in","r",stdin); freopen("t.out","w",stdout); int T,x,y; read(T); while (T--){ read(n); for (int i=1;i<=n;i++) read(H[i]),read(C[i]); for (int i=1;i<n;i++) read(x),read(y),add(x,y,++inum),add(y,x,++inum); h=0; dfs(1,0); dp(1,0); ld ans=B[bi[1]].Query(0); printf("%.0lf\n",(double)ans); //cout<<fixed<<setprecision(0)<<ans<<endl; cl(head); inum=0; cl(tag); cl(bi); for (int i=1;i<=bcnt;i++) B[i].clear(); bcnt=0; } return 0;}
阅读全文
0 0
- [二进制分组 dsu on tree 二次函数] Codechef KILLER Painting Tree
- [trick]dsu on tree
- dsu on tree
- [trick]dsu on tree
- Dsu on tree
- cf570D. Tree Requests(dsu on tree)
- Dsu on tree 神奇的暴力
- dsu on the tree 学习笔记
- codeforces600E. Lomsat gelral(dsu on tree)
- 通信 dsu on tree+线段树
- 启发式合并/dsu on tree 姿势
- 【dsu on tree】Codeforces600E[Lomsat gelral]题解
- [Dsu on tree]CodeForces 600 E
- [dsu on tree] BZOJ5040. 未来研究
- [CODECHEF]Prime Distance On Tree
- CodeChef PRIMEDSTPrime Distance On Tree
- 【codechef】Fibonacci Numbers on Tree
- codeforces 570 D. Tree Requests (dsu on the tree)
- Spring Boot学习笔记-Nginx+Jar包部署项目
- Unity3D学习(16)之初识DDD
- 文章标题
- 今天收到阿里巴巴一个电话面试
- babel-plugin-import不生效的问题
- [二进制分组 dsu on tree 二次函数] Codechef KILLER Painting Tree
- C++上机实验五——数组1
- linux内核分析1--反汇编分析
- 浅谈动态代理
- DFS的两种非递归的实现方法
- 图像处理与识别学习小结
- 吴恩达2014机器学习TIPS记录(第一周至第六周)
- 微服务学习笔记一:Spring Cloud简介
- App移动端项目管理