題目
二輪毒瘤題啊
辣雞洛谷竟然有卡樹剖的資料
還是\(loj\)可愛
首先這道題沒有帶修,設\(dp_\)表示以\(i\)為最高點的連通塊有多少個異或和為\(j\),\(g_=\sum_dp_\) (\(k\in tree(i)\)表示\(k\)在\(i\)子樹內部)
我們可以直接把每乙個權值\(fwt\)一下,大力合併就好了,合併直接對位相乘,只需要在最後\(fwt\)回來就好了
但是我們有了修改,就變成了一道非常噁心的\(ddp\)了
首先我們\(fwt\)肯定還是要\(fwt\)的,我們以下的\(dp\)都是\(fwt\)之後的
考慮我們的方程
\[dp_=dp_+dp_\times dp_
\]\[g_=dp_+g_
\]我們考慮把重兒子和輕兒子分開處理,也就是\(ddp\)了
設\(f'\)表示沒有處理重兒子的\(dp\)陣列,\(g'\)表示沒有處理重兒子的\(g\)陣列
我們可以寫成這樣的矩陣
\[\begin f_\\ 1\\ g_ \end \times \begin f' & f' & 0 \\ 0 & 1 & 0 \\ f' & f'+g' & 1 \end=\begin f_\\ 1\\ g_ \end
\]貓老師的部落格裡提到這個矩陣只有乙個地方是有用的,於是我們可以只存\(4\)個值來表示矩陣,從而大大優化常數
又因為我們\(fwt\)之後可以對於每一位單獨考慮,於是我們直接來上\(128\)棵線段樹分別維護每一位的值就好了
有乙個問題就是我們需要撤回乙個輕兒子的影響
設沒有這個輕兒子的時候為\(f'\),輕兒子影響為\(v\)
則有\[f=f'+f'\times v
\]則有
\[f'=\frac
\]但是如果\(1+v=0\),我們沒有辦法直接除掉這個影響
所以我們還需要對於每乙個點維護出其有多少個輕兒子的會使得\(f\)變成\(0\),以及沒有這些輕兒子的話\(f\)的值應該是多少
這樣我們就能解決這個問題了
但是細節還是有一堆,非常非常難寫
**
#include#include#include#include#define re register
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=30005;
const int mod=10007;
const int inv=5004;
inline int read()
struct ee[maxn<<1];
struct mat;
int n,num,len,m,q,__;
int head[maxn],son[maxn],sum[maxn],deep[maxn],fa[maxn],top[maxn],s[128],h[128],inv[mod+5];
int bot[maxn],dp[maxn][128],g[maxn][128],dfn[maxn],id[maxn],pos[maxn],val[maxn][128];
int h[maxn][128],tmp[maxn][128],p[maxn][128];
int l[maxn*3],r[maxn*3];
inline void add(int x,int y)
inline void fwt(int *f,int o)
}int dfs2(int x,int topf)
inline mat operator*(mat a,mat b)
struct segment_tree
mat query(int x,int y,int i)
inline void change(int i,mat k)
}}t[128];
void build(int x,int y,int i)
struct ee[maxn<<1];
struct mat;
int n,num,len,m,q,__;
int head[maxn],son[maxn],sum[maxn],deep[maxn],fa[maxn],top[maxn],s[128],h[128],inv[mod+5];
int bot[maxn],dp[maxn][128],g[maxn][128],dfn[maxn],id[maxn],pos[maxn],val[maxn][128];
int h[maxn][128],tmp[maxn][128],p[maxn][128];
int l[maxn*3],r[maxn*3],a[maxn],b[maxn],top,vis[maxn];
inline void add(int x,int y)
inline void fwt(int *f,int o)
}int dfs2(int x,int topf)
inline mat operator*(mat a,mat b)
struct segment_tree
mat query(const int x,const int y,re int i)
inline void change(re int i,mat k)
}}t[128];
void build(int x,int y,int i)
inline void modify(int x,int v)
else
now.a=(now.a+now.a*g.b)%mod;
now.d=(now.d-now.b+now.a+mod)%mod;
now.d=(now.d-pre.d+g.d+mod)%mod;
now.b=now.c=now.a;
val[x][i]=(val[x][i]*(g.b+1))%mod;
if((g.b+1)%mod==0) tmp[x][i]++;
else h[x][i]=(h[x][i]*(g.b+1))%mod;
pre=t[i].query(dfn[top[x]],dfn[bot[x]],1);
t[i].change(pos[x],now);
if(top[x]==1) break;
g=t[i].query(dfn[top[x]],dfn[bot[x]],1);
x=fa[top[x]];}}
for(re int i=0;i}signed main()
inv[1]=1;
for(re int i=2;ifor(re int x,y,i=1;ix=read(),y=read(),add(x,y),add(y,x);
deep[1]=1;dfs1(1);bot[1]=dfs2(1,1);
build(1,n,1);char op[10];int x,v,x;
q=read();
while(q--)
for(re int i=1;i<=mid;i++) vis[a[i]]=0;
for(re int i=0;ifwt(s,1);
x=read();printf("%d\n",s[x]);
}else
}return 0;
}
SDOI2017 切樹遊戲
一棵樹,每個點有點權,多次操作 1.單點修改乙個點的點權 2.詢問有多少棵子樹點權異或和為 k n leq 30000,k leq 128,q leq 30000 sol 動態 dp 為防止自己忘,再寫一遍 乙個點的 dp 值 sum dp dp 這樣就可以一條重鏈一起轉移 用線段樹維護重鏈上的轉移...
SDOI2017 切樹遊戲
設 f 表示 x 子樹中,所有包含 x 且異或和為 i 的連通塊數量,f 表示 x 子樹中異或和為 i 的連通塊數量。顯然,有公式 f f sum limits x f 現在考慮 f 的轉移。假如我們要合併 x 與某個兒子 y 的dp陣列,則顯然有公式 f sum limits k i f time...
SDOI2017 硬幣遊戲
考慮生成函式來做 g x 函式就是0 0 x 1 x s n s x n 就是最後s位必須填這個串,但是前面隨便填的方案數 然後列舉之前出現了哪個串 包括自己 如果沒有相交,就是fj x g x 還有就是有前字尾有相交部分,pji x 中的第k位,表示i的長度為m k的字首和j的長度為m k的字尾是...