【题目链接】

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+;
const int M = ;
const ll X = <<;
const ll Y = ; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} struct Edge {
int v,nxt;
}e[N<<];
int en=,front[N];
void adde(int u,int v)
{
e[++en]=(Edge){v,front[u]}; front[u]=en;
} int n,m,C,a[N][M],dfs_list[N],SZ,dfn; ll A,B,Q;
int dep[N],son[N],top[N],siz[N],fa[N],pl[N],L[N],R[N]; struct Tnode {
int u,l,r,c[M],g[M];
void maintain() ;
} T[N<<];
void Tnode::maintain() {
if(T[u].l==T[u].r) return ;
memset(c,,sizeof(c));
FOR(i,,m) FOR(j,,m-i)
c[i+j]=max(c[i+j],T[u<<].c[i]+T[u<<|].c[j]);
FOR(i,,m)
g[i]=max(T[u<<].g[i],T[u<<|].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>>;
build(u<<,l,mid);
build(u<<|,mid+,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>>;
if(x<=mid) update(u<<,x,A);
else update(u<<|,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>>;
if(L<=mid) query1(u<<,L,R,ans);
if(mid<R) query1(u<<|,L,R,ans);
}
}
void query2(int u,int L,int R,int* ans)
{
if(L<=T[u].l&&T[u].r<=R) {
FOR(i,,m) ans[i]=max(ans[i],T[u].g[i]);
} else {
int mid=T[u].l+T[u].r>>;
if(L<=mid) query2(u<<,L,R,ans);
if(mid<R) query2(u<<|,L,R,ans);
}
} void dfs1(int u)
{
siz[u]=; son[u]=;
trav(u,i) if(e[i].v!=fa[u]) {
int v=e[i].v;
fa[v]=u;
dep[v]=dep[u]+;
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(,pl[top[u]],pl[u],ans);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
query2(,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,,n) {
u=read(); adde(u,i);
}
FOR(i,,n) {
FOR(j,,m) a[i][j]=get_int();
sort(a[i]+,a[i]+m+);
}
dfs1(); dfs2(,);
build(,,SZ);
C=read();
FOR(i,,C) {
op=read(),u=read();
if(op==) {
FOR(j,,m) a[u][j]=get_int();
sort(a[u]+,a[u]+m+);
update(,L[u],a[u]);
} else {
v=read();
memset(ans1,,sizeof(ans1));
memset(ans2,,sizeof(ans2));
query1(,L[u],R[u],ans1);
if(u!=v) query2(fa[u],v,ans2);
int ans=;
FOR(i,,m)
ans=max(ans,ans1[i]+ans2[m-i]);
printf("%d\n",ans);
}
}
return ;
}

P.S.拿线段树DP,这道题实在是太太太太太神辣

Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)的更多相关文章

  1. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  2. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  3. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  4. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  5. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  6. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  7. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  8. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  9. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  10. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

随机推荐

  1. 如何在windows环境中搭建apache+subversion(ZT)

    我一直有一个想法就是在本机上象scm一样的搭建一个subversion服务器,然后每天写完代码的时候提交一下,这种感觉好好哦,之前我在windows环境中搭建过纯subversion的服务器兴奋过一阵 ...

  2. 是什么让 Ubuntu 选用 Qt 而不是 GTK?

    是什么让 Ubuntu 选用 Qt 而不是 GTK? 一个正在发生的事实,Ubuntu正在不断Qt化!我曾一直在抱怨的Software Center,今日一看源码,竟然有softwarecenter/ ...

  3. Filter过滤非法字符

    示例:定义一个Filter,用于用户发言中出现的“晕”字,即如果没有这个字则允许发言,如果有这个字则不允许发言并提示错误. CharForm.jsp <%@ page language=&quo ...

  4. 10个最佳的PHP图像操作库

    Thomas Boutell 以及众多的开发者创造了以GD图形库闻名的一个图形软件库,用于动态的图形计算. GD提供了对于诸如C, Perl, Python, PHP, OCaml等等诸多编程语言的支 ...

  5. 进程间通信机制<转>

    1   文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待.因此,进程不必使用文件I/O操作,只需简单的指针操作就可读取和修改文件的内容. ...

  6. poj 1699 Best Sequence (搜索技巧 剪枝 dfs)

    题目链接 题意:给出几个基因片段,要求你将它们排列成一个最短的序列,序列中使用了所有的基因片段,而且不能翻转基因. 分析:先计算出add数组,再dfs枚举. 空间复杂度O(n*n),  最坏时间复杂度 ...

  7. poj3207 Ikki’s Story IV – Panda’s Trick

    2-SAT. tarjan缩点.强连通分量的点要选一起选. #include<cstdio> #include<algorithm> #include<cstring&g ...

  8. EASYUI+MVC4通用权限管理平台

    通用权限案例平台在经过几年的实际项目使用,并取得了不错的用户好评.在平台开发完成后,特抽空总结一下平台知识,请各位在以后的时间里,关注博客的更新. 1.EASYUI+MVC4通用权限管理平台--前言 ...

  9. UVa 11584 Partitioning by Palindromes【DP】

    题意:给出一个字符串,问最少能够划分成多少个回文串 dp[i]表示以第i个字母结束最少能够划分成的回文串的个数 dp[i]=min(dp[i],dp[j]+1)(如果从第j个字母到第i个字母是回文串) ...

  10. UVA 11426 GCD-Extreme(II) ★ (欧拉函数)

    题意 求Σ{1<=i<N} Σ{i<j<=N} GCD(i, j)     (N<=4000000) 分析 原始思路 暴力求明显是不行的,我们把式子简化形式一下发现它可以 ...