Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)
2016-03-27 16:06
183 查看
【题目链接】
http://www.tsinsen.com/A1219
【题意】
给定一棵树,a[u][i]代表u结点分配i人的收益,可以随时改变a[u],查询(u,v)代表在u子树的所有节点,在u->v(不含u)路径上的节点分配人数的最优收益。
【思路】
树链剖分:构造重链时先访问重儿子,因此一个重链的区间连续,同时一个子树的区间连续。
查询分为两部分:构造在u子树内分配人数i的最大收益ans1[i],以及构造在u->v路径上一个结点分配人数i的最大收益ans2[i]。则ans=max{ ans1[i]+ans2[m-i] }。
考虑链剖:一棵线段树维护一条重链上的两类信息,c[i]为任意分配的最优,g[i]为在其中一个分配的最优。则ans1可以通过询问u子树的连续区间得,ans2可以询问u->v路径上的重链得。
需要注意的是线段树中c的递推应该逆序枚举,否则覆盖原值。
【代码】
P.S.拿线段树DP,这道题实在是太太太太太神辣
http://www.tsinsen.com/A1219
【题意】
给定一棵树,a[u][i]代表u结点分配i人的收益,可以随时改变a[u],查询(u,v)代表在u子树的所有节点,在u->v(不含u)路径上的节点分配人数的最优收益。
【思路】
树链剖分:构造重链时先访问重儿子,因此一个重链的区间连续,同时一个子树的区间连续。
查询分为两部分:构造在u子树内分配人数i的最大收益ans1[i],以及构造在u->v路径上一个结点分配人数i的最大收益ans2[i]。则ans=max{ ans1[i]+ans2[m-i] }。
考虑链剖:一棵线段树维护一条重链上的两类信息,c[i]为任意分配的最优,g[i]为在其中一个分配的最优。则ans1可以通过询问u子树的连续区间得,ans2可以询问u->v路径上的重链得。
需要注意的是线段树中c的递推应该逆序枚举,否则覆盖原值。
【代码】
#include<set> #include<cmath> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) #define FOR(a,b,c) for(int a=(b);a<=(c);a++) using namespace std; typedef long long ll; const int N = 4e4+10; const int M = 55; const ll X = 1<<16; const ll Y = 2147483647; ll read() { char c=getchar(); ll f=1,x=0; while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x*f; } struct Edge { int v,nxt; }e[N<<1]; int en=1,front ; void adde(int u,int v) { e[++en]=(Edge){v,front[u]}; front[u]=en; } int n,m,C,a [M],dfs_list ,SZ,dfn; ll A,B,Q; int dep ,son ,top ,siz ,fa ,pl ,L ,R ; struct Tnode { int u,l,r,c[M],g[M]; void maintain() ; } T[N<<1]; void Tnode::maintain() { if(T[u].l==T[u].r) return ; memset(c,0,sizeof(c)); FOR(i,0,m) FOR(j,0,m-i) c[i+j]=max(c[i+j],T[u<<1].c[i]+T[u<<1|1].c[j]); FOR(i,0,m) g[i]=max(T[u<<1].g[i],T[u<<1|1].g[i]); } void build(int u,int l,int r) { T[u].u=u,T[u].l=l,T[u].r=r; if(l==r) { memcpy(T[u].c,a[dfs_list[l]],sizeof(T[u].c)); memcpy(T[u].g,a[dfs_list[l]],sizeof(T[u].g)); return ; } int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); T[u].maintain(); } void update(int u,int x,int* A) { if(T[u].l==T[u].r) { memcpy(T[u].c,A,sizeof(T[u].c)); memcpy(T[u].g,A,sizeof(T[u].g)); } else { int mid=T[u].l+T[u].r>>1; if(x<=mid) update(u<<1,x,A); else update(u<<1|1,x,A); T[u].maintain(); } } void query1(int u,int L,int R,int* ans) { if(L<=T[u].l&&T[u].r<=R) { for(int i=m;i;i--) for(int j=i;j;j--) //逆序枚举i 避免覆盖 ans[i]=max(ans[i],ans[i-j]+T[u].c[j]); } else { int mid=T[u].l+T[u].r>>1; if(L<=mid) query1(u<<1,L,R,ans); if(mid<R) query1(u<<1|1,L,R,ans); } } void query2(int u,int L,int R,int* ans) { if(L<=T[u].l&&T[u].r<=R) { FOR(i,0,m) ans[i]=max(ans[i],T[u].g[i]); } else { int mid=T[u].l+T[u].r>>1; if(L<=mid) query2(u<<1,L,R,ans); if(mid<R) query2(u<<1|1,L,R,ans); } } void dfs1(int u) { siz[u]=1; son[u]=0; trav(u,i) if(e[i].v!=fa[u]) { int v=e[i].v; fa[v]=u; dep[v]=dep[u]+1; dfs1(v); siz[u]+=siz[v]; if(siz[v]>siz[son[u]]) son[u]=v; } } void dfs2(int u,int tp) { top[u]=tp; pl[u]=L[u]=++SZ; dfs_list[SZ]=u; if(son[u]) dfs2(son[u],tp); trav(u,i) if(e[i].v!=fa[u]&&e[i].v!=son[u]) dfs2(e[i].v,e[i].v); R[u]=SZ; } void query2(int u,int v,int*ans) { while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); query2(1,pl[top[u]],pl[u],ans); u=fa[top[u]]; } if(dep[u]>dep[v]) swap(u,v); query2(1,pl[u],pl[v],ans); } int get_int() { A=((A^B)+(B/X)+(ll)(B*X))&Y; B=((A^B)+(A/X)+(ll)(A*X))&Y; return (int)(A^B)%Q; } int ans1[M],ans2[M]; int main() { // freopen("in.in","r",stdin); // freopen("out.out","w",stdout); n=read(),m=read(),A=read(),B=read(),Q=read(); int op,u,v; FOR(i,2,n) { u=read(); adde(u,i); } FOR(i,1,n) { FOR(j,1,m) a[i][j]=get_int(); sort(a[i]+1,a[i]+m+1); } dfs1(1); dfs2(1,1); build(1,1,SZ); C=read(); FOR(i,1,C) { op=read(),u=read(); if(op==0) { FOR(j,1,m) a[u][j]=get_int(); sort(a[u]+1,a[u]+m+1); update(1,L[u],a[u]); } else { v=read(); memset(ans1,0,sizeof(ans1)); memset(ans2,0,sizeof(ans2)); query1(1,L[u],R[u],ans1); if(u!=v) query2(fa[u],v,ans2); int ans=0; FOR(i,0,m) ans=max(ans,ans1[i]+ans2[m-i]); printf("%d\n",ans); } } return 0; }
P.S.拿线段树DP,这道题实在是太太太太太神辣
相关文章推荐
- 揭开Spark Streaming神秘面纱② - ReceiverTracker 与数据导入
- Lua入门学习资料
- bootstrap modal 添加input Firefox报错
- java学习笔记之java如何快速入门
- 【转载】jdk、jre、jvm等名词解释
- 第5周-项目1-三角形类锥形(4)
- 《Linux内核设计与实现》第5章读书整理
- Memory Management
- C语言指针的指针作用(返回值)之二
- VMware workstation NAT方式无法连接外网
- samba permission configuration
- C++中map容器的使用
- mybatis连接mysql数据库插入中文乱码
- Java并发编程:Lock
- 周赛(一)
- HDU 1056
- win10企业版安装CAD Electrical2016提示缺少.net4.5该怎么办?
- 03-27-学习进度条
- Uboot启动分析之Start.S
- View setSystemUiVisible 测试