Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)
【题目链接】
【题意】
给定一棵树,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的递推应该逆序枚举,否则覆盖原值。
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 const int N = 4e4+10; 15 const int M = 55; 16 const ll X = 1<<16; 17 const ll Y = 2147483647; 18 19 ll read() { 20 char c=getchar(); 21 ll f=1,x=0; 22 while(!isdigit(c)) { 23 if(c=='-') f=-1; c=getchar(); 24 } 25 while(isdigit(c)) 26 x=x*10+c-'0',c=getchar(); 27 return x*f; 28 } 29 30 struct Edge { 31 int v,nxt; 32 }e[N<<1]; 33 int en=1,front[N]; 34 void adde(int u,int v) 35 { 36 e[++en]=(Edge){v,front[u]}; front[u]=en; 37 } 38 39 int n,m,C,a[N][M],dfs_list[N],SZ,dfn; ll A,B,Q; 40 int dep[N],son[N],top[N],siz[N],fa[N],pl[N],L[N],R[N]; 41 42 struct Tnode { 43 int u,l,r,c[M],g[M]; 44 void maintain() ; 45 } T[N<<1]; 46 void Tnode::maintain() { 47 if(T[u].l==T[u].r) return ; 48 memset(c,0,sizeof(c)); 49 FOR(i,0,m) FOR(j,0,m-i) 50 c[i+j]=max(c[i+j],T[u<<1].c[i]+T[u<<1|1].c[j]); 51 FOR(i,0,m) 52 g[i]=max(T[u<<1].g[i],T[u<<1|1].g[i]); 53 } 54 55 void build(int u,int l,int r) 56 { 57 T[u].u=u,T[u].l=l,T[u].r=r; 58 if(l==r) { 59 memcpy(T[u].c,a[dfs_list[l]],sizeof(T[u].c)); 60 memcpy(T[u].g,a[dfs_list[l]],sizeof(T[u].g)); 61 return ; 62 } 63 int mid=l+r>>1; 64 build(u<<1,l,mid); 65 build(u<<1|1,mid+1,r); 66 T[u].maintain(); 67 } 68 void update(int u,int x,int* A) 69 { 70 if(T[u].l==T[u].r) { 71 memcpy(T[u].c,A,sizeof(T[u].c)); 72 memcpy(T[u].g,A,sizeof(T[u].g)); 73 } else { 74 int mid=T[u].l+T[u].r>>1; 75 if(x<=mid) update(u<<1,x,A); 76 else update(u<<1|1,x,A); 77 T[u].maintain(); 78 } 79 } 80 void query1(int u,int L,int R,int* ans) 81 { 82 if(L<=T[u].l&&T[u].r<=R) { 83 for(int i=m;i;i--) for(int j=i;j;j--) //逆序枚举i 避免覆盖 84 ans[i]=max(ans[i],ans[i-j]+T[u].c[j]); 85 } else { 86 int mid=T[u].l+T[u].r>>1; 87 if(L<=mid) query1(u<<1,L,R,ans); 88 if(mid<R) query1(u<<1|1,L,R,ans); 89 } 90 } 91 void query2(int u,int L,int R,int* ans) 92 { 93 if(L<=T[u].l&&T[u].r<=R) { 94 FOR(i,0,m) ans[i]=max(ans[i],T[u].g[i]); 95 } else { 96 int mid=T[u].l+T[u].r>>1; 97 if(L<=mid) query2(u<<1,L,R,ans); 98 if(mid<R) query2(u<<1|1,L,R,ans); 99 } 100 } 101 102 void dfs1(int u) 103 { 104 siz[u]=1; son[u]=0; 105 trav(u,i) if(e[i].v!=fa[u]) { 106 int v=e[i].v; 107 fa[v]=u; 108 dep[v]=dep[u]+1; 109 dfs1(v); 110 siz[u]+=siz[v]; 111 if(siz[v]>siz[son[u]]) son[u]=v; 112 } 113 } 114 void dfs2(int u,int tp) 115 { 116 top[u]=tp; pl[u]=L[u]=++SZ; dfs_list[SZ]=u; 117 if(son[u]) dfs2(son[u],tp); 118 trav(u,i) if(e[i].v!=fa[u]&&e[i].v!=son[u]) 119 dfs2(e[i].v,e[i].v); 120 R[u]=SZ; 121 } 122 void query2(int u,int v,int*ans) 123 { 124 while(top[u]!=top[v]) { 125 if(dep[top[u]]<dep[top[v]]) swap(u,v); 126 query2(1,pl[top[u]],pl[u],ans); 127 u=fa[top[u]]; 128 } 129 if(dep[u]>dep[v]) swap(u,v); 130 query2(1,pl[u],pl[v],ans); 131 } 132 133 int get_int() 134 { 135 A=((A^B)+(B/X)+(ll)(B*X))&Y; 136 B=((A^B)+(A/X)+(ll)(A*X))&Y; 137 return (int)(A^B)%Q; 138 } 139 140 int ans1[M],ans2[M]; 141 142 int main() 143 { 144 // freopen("in.in","r",stdin); 145 // freopen("out.out","w",stdout); 146 n=read(),m=read(),A=read(),B=read(),Q=read(); 147 int op,u,v; 148 FOR(i,2,n) { 149 u=read(); adde(u,i); 150 } 151 FOR(i,1,n) { 152 FOR(j,1,m) a[i][j]=get_int(); 153 sort(a[i]+1,a[i]+m+1); 154 } 155 dfs1(1); dfs2(1,1); 156 build(1,1,SZ); 157 C=read(); 158 FOR(i,1,C) { 159 op=read(),u=read(); 160 if(op==0) { 161 FOR(j,1,m) a[u][j]=get_int(); 162 sort(a[u]+1,a[u]+m+1); 163 update(1,L[u],a[u]); 164 } else { 165 v=read(); 166 memset(ans1,0,sizeof(ans1)); 167 memset(ans2,0,sizeof(ans2)); 168 query1(1,L[u],R[u],ans1); 169 if(u!=v) query2(fa[u],v,ans2); 170 int ans=0; 171 FOR(i,0,m) 172 ans=max(ans,ans1[i]+ans2[m-i]); 173 printf("%d\n",ans); 174 } 175 } 176 return 0; 177 }
P.S.拿线段树DP,这道题实在是太太太太太神辣
posted on 2016-03-27 16:06 hahalidaxin 阅读(506) 评论(1) 编辑 收藏 举报