Description
Professor Zhang has a rooted tree, whose vertices are conveniently labeled by
1,2,...,n
. And the
i
-th vertex is assigned with weight
Solution
比赛时根本不知所措。。
赛后看题解,orz出题人脑洞
首先显然dp
令
dp[i]
表示节点
i
的
由定义
f[i]=dp[i]+w[i]
而
dp
的转移也是显然的:
dp[i]=maxj is i′s ancestordp[j]+w[j] opt w[i]
关键是这个转移好像不好搞。。
标程给了一个类似meet in the middle的转移方法
先考虑序列上的简化问题
首先观察到题目的数据范围很奇怪
每个数字w[i]可以拆成
a<<8|b
的形式(即
a
是
定义
ds(i,x,y)
表示扫描到点
i
,某个之前的
然后你扫描到当前的
i
,知道了
在树上和在序列上好像没差吧。。每个节点备份一下
ds
的状态回溯的时候还原现场即可。
当然,
ds
的第一维是完全可以省掉的(滚掉),然后备份的空间复杂度为
O(28∗n)
,是可以过掉的。
感觉只搞过meet in the middle 的搜索题,这种出现在dp转移里的meet in the middle 也是极有借鉴价值的(看有一维直接消失了)。
Code
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vec;
typedef priority_queue<int> pq;
#define pb push_back
#define ph push
#define fi first
#define se second
template<class T>void Max(T &a,T b){if(a<b)a=b;}
template<class T>void Min(T &a,T b){if(a>b||a==-1)a=b;}
template<class T>void rd(T &a){
a=0;char c;
while(c=getchar(),!isdigit(c));
do a=a*10+(c^48);
while(c=getchar(),isdigit(c));
}
template<class T>void nt(T x){
if(!x)return;
nt(x/10);
putchar(48+x%10);
}
template<class T>void pt(T x){
if(!x)putchar('0');
else nt(x);
}
const int M=65540;
const int N=260;
const int P=1e9+7;
typedef unsigned ud;
int n,w[M],fa[M];
ud ds[N][N],f[M][N];
struct Edge{
int to,nxt;
}edge[M];
int head[M],tot_edge,flag;
inline void add_edge(int a,int b){
edge[tot_edge]=(Edge){b,head[a]};
head[a]=tot_edge++;
}
string opt;
inline int calc(ud a,ud b){
if(!flag)return a&b;
if(flag==1)return a|b;
return a^b;
}
int ans,cnt[N];
template<class T>void Mod_add(T &a,T b){
if((a+=b)>=P)a-=P;
}
void dfs(int v){
ud dp=0;
ud a=w[v]>>8,b=w[v]&255;
for(ud x=0;x<256;++x){
if(cnt[x])
Max(dp,(ud){ds[x][b]+(calc(a,x)<<8)});
}
Mod_add(ans,(int){(1ll*v*(dp+w[v]))%P});
for(ud x=0;x<256;++x){//后8位
f[v][x]=ds[a][x];
Max(ds[a][x],calc(x,b)+dp);
}
++cnt[a];
for(int i=head[v];~i;i=edge[i].nxt)
dfs(edge[i].to);
--cnt[a];
for(int i=0;i<256;++i)
ds[a][i]=f[v][i];
}
inline void gao(){
memset(head,-1,sizeof(head));
tot_edge=0;
cin>>n>>opt;
for(int i=1;i<=n;++i)rd(w[i]);
for(int i=2;i<=n;++i)rd(fa[i]),add_edge(fa[i],i);
if(opt[0]=='A')flag=0;
if(opt[0]=='O')flag=1;
if(opt[0]=='X')flag=2;
ans=0;
dfs(1);
pt(ans);
putchar('\n');
}
//#define LOCAL
int main(){
#ifdef LOCAL
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
#endif
int _;for(cin>>_;_--;)gao();
return 0;
}