山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + 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的递推应该逆序枚举,否则覆盖原值。

 

【代码】

 

  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  阅读(501)  评论(1编辑  收藏  举报