【LOJ】#2269. 「SDOI2017」切树游戏
题解
把所有的数组一开始就FWT好然后再IFWT回去可以减小常数
从13s跑到0.7s……
可以参照immortalCO的论文,感受一下毒瘤的动态动态DP
就是用数据结构维护线性递推的矩阵的乘积
由于所有轻儿子\(F(z) + z^{0}\)的乘积做除法太麻烦,我们用一个线段树维护每个点所有的轻儿子即可
代码
#include <bits/stdc++.h>
#define enter putchar('\n')
#define space putchar(' ')
#define fi first
#define se second
#define MAXN 30005
//#define ivorysi
#define pii pair<int,int>
#define pb push_back
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
const int MOD = 10007,Inv2 = 5004;
int mul(int a,int b) {
return a * b % MOD;
}
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
struct Enode {
int to,next;
}E[MAXN * 2];
int N,M,head[MAXN],sumE,val[MAXN],pos[MAXN];
int son[MAXN],siz[MAXN],fa[MAXN],dep[MAXN],top[MAXN];
int rt[MAXN],dfn[MAXN],L[MAXN],id[MAXN],Lcnt,idx;
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
struct Poly {
int p[128];
Poly() {memset(p,0,sizeof(p));}
friend void FWT(Poly &f) {
for(int i = 1 ; i < M ; i <<= 1) {
for(int j = 0 ; j < M ; j += (i << 1)) {
for(int k = 0 ; k < i ; ++k) {
int a0 = f.p[j + k],a1 = f.p[j + i + k];
f.p[j + k] = inc(a0,a1);
f.p[j + i + k] = inc(a0,MOD - a1);
}
}
}
}
friend void IFWT(Poly &f) {
for(int i = 1 ; i < M ; i <<= 1) {
for(int j = 0 ; j < M ; j += (i << 1) ) {
for(int k = 0 ; k < i ; ++k) {
int a0 = f.p[j + k],a1 = f.p[j + i + k];
f.p[j + k] = mul(inc(a0,a1),Inv2);
f.p[j + i + k] = mul(inc(a0,MOD - a1),Inv2);
}
}
}
}
friend Poly operator * (Poly a,Poly b) {
Poly c;
for(int i = 0 ; i < M ; ++i) c.p[i] = mul(a.p[i],b.p[i]);
return c;
}
friend Poly operator + (const Poly &a,const Poly &b) {
Poly c;
for(int i = 0 ; i < M ; ++i) c.p[i] = inc(a.p[i],b.p[i]);
return c;
}
friend Poly operator - (const Poly &a,const Poly &b) {
Poly c;
for(int i = 0 ; i < M ; ++i) c.p[i] = inc(a.p[i],MOD - b.p[i]);
return c;
}
}F[MAXN],H[MAXN],one,LH[MAXN],LF[MAXN];
struct Matrix {
Poly a,b,c,d;
friend Matrix operator * (const Matrix &s,const Matrix &t) {
Matrix r;
r.a = s.a * t.a;
r.b = s.b + s.a * t.b;
r.c = s.c * t.a + t.c;
r.d = s.c * t.b + s.d + t.d;
return r;
}
};
struct node {
int lc,rc,L,R;
Matrix m;
}tr[MAXN * 5];
int Ncnt;
vector<Poly> Tr[MAXN];
vector<int> Lson;
void update(int u) {
tr[u].m = tr[tr[u].rc].m * tr[tr[u].lc].m;
}
void build(int &u,int l,int r){
u = ++Ncnt;
tr[u].L = l;tr[u].R = r;
if(l == r) {
int k = L[r];
Poly t;t.p[val[k]] = 1;FWT(t);
tr[u].m.a = tr[u].m.b = tr[u].m.c = LF[k] * t;
tr[u].m.d = LH[k] + tr[u].m.a;
return ;
}
int mid = (l + r) >> 1;
build(tr[u].lc,l,mid);
build(tr[u].rc,mid + 1,r);
update(u);
}
void buildLt(int id,int u,int l,int r) {
if(l == r) {
int k = Lson[l - 1];
Tr[id][u] = F[k] + one;
pos[k] = u;
return;
}
int mid = (l + r) >> 1;
buildLt(id,u << 1,l,mid);
buildLt(id,u << 1 | 1,mid + 1,r);
Tr[id][u] = Tr[id][u << 1] * Tr[id][u << 1 | 1];
}
void CalcAgain(int u,int pos,int k) {
if(tr[u].L == tr[u].R) {
Poly t;t.p[val[k]] = 1;FWT(t);
tr[u].m.a = tr[u].m.b = tr[u].m.c = LF[k] * t;
tr[u].m.d = tr[u].m.a + LH[k];
return ;
}
int mid = (tr[u].L + tr[u].R) >> 1;
if(pos <= mid) CalcAgain(tr[u].lc,pos,k);
else CalcAgain(tr[u].rc,pos,k);
update(u);
}
void Change(int u) {
while(u) {
CalcAgain(rt[id[u]],dfn[u],u);
u = top[u];
if(fa[u]) {
F[u] = tr[rt[id[u]]].m.c;
LH[fa[u]] = LH[fa[u]] - H[u] + tr[rt[id[u]]].m.d;
H[u] = tr[rt[id[u]]].m.d;
int t = pos[u];Tr[fa[u]][t] = F[u] + one;t >>= 1;
while(t) {
Tr[fa[u]][t] = Tr[fa[u]][t << 1] * Tr[fa[u]][t << 1 | 1];
t >>= 1;
}
LF[fa[u]] = Tr[fa[u]][1];
}
u = fa[u];
}
}
void dfs1(int u) {
siz[u] = 1;dep[u] = dep[fa[u]] + 1;
F[u].p[val[u]] = 1;FWT(F[u]);
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u]) {
fa[v] = u;
dfs1(v);
F[u] = F[u] * (F[v] + one);
H[u] = H[u] + H[v];
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
H[u] = H[u] + F[u];
}
void dfs2(int u) {
LF[u] = one;
Lson.clear();
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u] && v != son[u]) {
Lson.pb(v);
LF[u] = LF[u] * (F[v] + one);
LH[u] = LH[u] + H[v];
}
}
if(Lson.size()) {
Tr[u].resize(Lson.size() * 4 + 5);
buildLt(u,1,1,Lson.size());
}
if(!top[u]) {top[u] = u;++Lcnt;idx = 0;}
L[++idx] = u;id[u] = Lcnt;dfn[u] = idx;
if(son[u]) {
top[son[u]] = top[u];
dfs2(son[u]);
}
else {
build(rt[Lcnt],1,idx);
return;
}
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u] && v != son[u]) {
dfs2(v);
}
}
}
void Init() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) read(val[i]);
int u,v;
for(int i = 1 ; i < N ; ++i) {
read(u);read(v);add(u,v);add(v,u);
}
one.p[0] = 1;
FWT(one);
dfs1(1);dfs2(1);
}
void Solve() {
int Q;char op[25];int x,y;
read(Q);
for(int i = 1 ; i <= Q ; ++i) {
scanf("%s",op + 1);
read(x);
if(op[1] == 'Q') {
Poly t = tr[rt[id[1]]].m.d;IFWT(t);
out(t.p[x]);enter;
}
else {
read(y);
val[x] = y;Change(x);
}
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}
【LOJ】#2269. 「SDOI2017」切树游戏的更多相关文章
- loj#2269. 「SDOI2017」切树游戏
还是loj的机子快啊... 普通的DP不难想到,设F[i][zt]为带上根玩出zt的方案数,G[i][zt]为子树中的方案数,后面是可以用FWT优化的 主要是复习了下动态DP #include< ...
- LOJ2269. 「SDOI2017」切树游戏 [FWT,动态DP]
LOJ 思路 显然是要DP的.设\(dp_{u,i}\)表示\(u\)子树内一个包含\(u\)的连通块异或出\(i\)的方案数,发现转移可以用FWT优化,写成生成函数就是这样的: \[ dp_{u}= ...
- LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)
题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...
- Loj #2570. 「ZJOI2017」线段树
Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...
- @loj - 2004@ 「SDOI2017」硬币游戏
目录 @description@ @solution@ @accepted code@ @details@ @description@ 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数 ...
- LOJ #2005. 「SDOI2017」相关分析 线段树维护回归直线方程
题目描述 \(Frank\) 对天文学非常感兴趣,他经常用望远镜看星星,同时记录下它们的信息,比如亮度.颜色等等,进而估算出星星的距离,半径等等. \(Frank\) 不仅喜欢观测,还喜欢分析观测到的 ...
- LOJ#2983. 「WC2019」数树
传送门 抄题解 \(Task0\),随便做一下,设 \(cnt\) 为相同的边的个数,输出 \(y^{n-cnt}\) \(Task1\),给定其中一棵树 设初始答案为 \(y^n\),首先可以发现, ...
- LOJ 6436 「PKUSC2018」神仙的游戏——思路+卷积
题目:https://loj.ac/problem/6436 看题解才会. 有长为 i 的 border ,就是有长为 n-i 的循环节. 考虑如果 x 位置上是 0 . y 位置上是 1 ,那么长度 ...
- @loj - 2093@ 「ZJOI2016」线段树
目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Yuuka 遇到了一个题目:有一个序列 a1,a2,..., ...
随机推荐
- 【BZOJ1047】[HAOI2007]理想的正方形(单调队列,动态规划)
[BZOJ1047][HAOI2007]理想的正方形(单调队列,动态规划) 题面 BZOJ 洛谷 题解 直接一个单调队列维护一下没给点和它前面的\(n\)个位置的最大值,再用一次单调队列维护连续\(n ...
- 洛谷 P2336 [SCOI2012]喵星球上的点名 解题报告
P2336 [SCOI2012]喵星球上的点名 题目描述 a180285 幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有 \(N\) 个喵星人,每个喵星人的 ...
- 转载:C++中两个类中互相包含对方对象的指针问题
原文链接:http://www.cnblogs.com/hanxi/archive/2012/07/25/2608068.html 前几天很不爽,因为C++中两个类中互相包含对方对象的指针编译时提示某 ...
- Link Cut Tree 总结
Link-Cut-Tree Tags:数据结构 ##更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1027479 一.概述 \(LCT\),动态树的一种,又可以 ...
- # 20155337 2016-2017-2 《Java程序设计》第六周学习总结
20155337 2016-2017-2 <Java程序设计>第六周学习总结 教材学习内容总结 •串流(Stream): 数据有来源及目的地,衔接两者的是串流对象.如果要将数据从来源取出, ...
- 第14月第1天 uialterview 键盘 uibutton圆角
1. 在IOS 8之后 当UIAlertView 和keyboard 同时出现时,会出现键盘闪现的情况 所以就修正UIAlertView http://blog.sina.com.cn/s/blog_ ...
- Chrome插件:gitlab activity dashboard background-color
背景 我一般都是在activity dashboard页看同事的提交记录,这样只要我有权限的项目有人提交了我就能够知道,虽然提交的具体代码压根不看.......但至少能够了解各个项目的开发情况(如果大 ...
- 判断gps是否在国内
参考文章:[WP7]判断GPS坐标是否在中国 根据国家行政边界判定(光线投射算法) 按需求调整了原文中的部分边界值,测试几组边界附近内外坐标,结果较为准确. /** * 判断GPS坐标是否在多边形中 ...
- mysql 1045 access denied for user 解决方法
提示:1045 access denied for user 'root'@'localhost' using password yes方法一: # /etc/init.d/mysql stop # ...
- CodeForces Contest #1114: Round #538 (Div. 2)
比赛传送门:CF #1114. 比赛记录:点我. 又 FST 了. [A]Got Any Grapes? 题意简述: 有三个人,第一个人需要吃绿色葡萄至少 \(a\) 个,第二个人需要吃绿色和紫色葡萄 ...