基于变换合并的树上动态 DP 的链分治算法 & SDOI2017 切树游戏(cut)解题报告
切了一晚树心态崩了。
你问我怎么求异或逆卷积。
我,我。我???我!!!!!才不会说是把FWT后的数组每个求个逆元呢。。。。。。。
怎么模数为质数还有没有逆元的操作啊!!!!!
对于10007的倍数没有逆元的情况,标程的方法是维护非0部分的积和0的个数,这样就可减了
-Claris
不然就要打用数据结构维护轻儿子的( t o p − t r e e ? top-tree? top−tree?)
AC Code:
#include
#define maxn 30005
#define maxm 128
#define mod 10007
using namespace std;
int n,m;
int inv[mod]={1,1};
int w[maxn],v[maxn][maxm],cg0[maxn][maxm],g[maxn][maxm],gu[maxn][maxm],val[maxm][maxm],ls[maxn][maxm],rs[maxn][maxm],su[maxn][maxm],sum[maxn][maxm];
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e=0;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
void FWT(int *a,int tp){
static int c[2] = {(mod+1)/2,1};
for(int L=2;L<=m;L<<=1)
for(int l=L>>1,st=0;st<m;st+=L)
for(int k=st;k<st+l;k++)
{
int x = a[k] , y = a[k+l];
a[k] = (x + y) * c[tp==1] % mod ,
a[k+l] = (x-y) * c[tp==1] % mod;
}
}
int siz[maxn],son[maxn],fa[maxn],ch[maxn][2],id[maxn],pos[maxn],tot,rt;
void dfs1(int now,int ff){
siz[now] = 1 , son[now] = -1;
for(int i=info[now];i;i=Prev[i])
if(to[i]!=ff){
dfs1(to[i],now);
siz[now] += siz[to[i]];
if(son[now] == -1 || siz[to[i]] > siz[son[now]])
son[now] = to[i];
}
}
void upd(int now){
int lc = ch[now][0] , rc = ch[now][1];
for(int i=0;i<m;i++)
{
sum[now][i] = sum[lc][i] * sum[rc][i] % mod * v[now][i] % mod * (cg0[now][i]<=0) *g[now][i] % mod;
rs[now][i] = (rs[rc][i] + (cg0[now][i]<=0)*g[now][i]*(rs[lc][i]+1)%mod*v[now][i]%mod*sum[rc][i])%mod;
ls[now][i] = (ls[lc][i] + (cg0[now][i]<=0)*g[now][i]*(ls[rc][i]+1)%mod*v[now][i]%mod*sum[lc][i])%mod;
int tmp = (su[now][i]+mod)%mod;
su[now][i] = (su[lc][i] + su[rc][i] +
(rs[lc][i]+1) * (ls[rc][i]+1)% mod
* (cg0[now][i]<=0)*g[now][i] % mod * v[now][i] % mod
+ gu[now][i]) % mod;
}
}
void upd2(int now,int to,int tp){
for(int i=0;i<m;i++){
if((ls[now][i] + 1) % mod == 0)
cg0[to][i] += tp;
else
g[to][i] = g[to][i] * (tp == 1 ? ls[now][i] + 1 : inv[(ls[now][i]+1+mod)%mod]) % mod;
gu[to][i] = (gu[to][i] + tp * su[now][i]) % mod;
}
}
int Build(int l,int r,int pfa){
if(l>r) return 0;
int L = l , R = r , mid , haf = (siz[pos[l]] - (r+1<=pfa ? siz[pos[r+1]] : 0)) / 2;
for(;L<R;){
mid = (L+R) >> 1;
if(siz[pos[l]] - siz[pos[mid]] >= haf) R = mid;
else L = mid + 1;
}
int now = pos[L];
fa[ch[now][0] = Build(l,L-1,pfa)] = now;
fa[ch[now][1] = Build(L+1,r,pfa)] = now;
upd(now);
//FWT(su[now],-1);
//printf("%d %d %d\n",now,ch[now][0],ch[now][1]);
//for(int i=0;i
//FWT(su[now],1);
return now;
}
int dfs2(int now,int ff){
int be = tot + 1 , ed;
for(int i=now;i!=-1;i=son[i])
pos[id[i] = ++tot] = i;
ed = tot;
for(int p=now;p!=-1;p=son[p])
for(int i=info[p];i;i=Prev[i])
if(!id[to[i]]){
int tmp = dfs2(to[i],p);
fa[tmp] = p;
upd2(tmp,p,1);
}
return Build(be,ed,ed);
}
int isr(int x){ return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x; }
int main(){
scanf("%d%d",&n,&m);
for(int i=2;i<mod;i++)
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
v[i][w[i]] = 1;
FWT(v[i],1);
}
for(int i=0;i<m;i++){
val[i][i] = 1;
FWT(val[i],1);
}
for(int i=0;i<=n;i++)
for(int j=0;j<m;j++)
g[i][j] = sum[i][j] = 1;
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
Node(u,v),Node(v,u);
}
dfs1(1,0),rt=dfs2(1,0);
int q;
scanf("%d",&q);
char S[10];
for(int x,y;q--;){
scanf("%s",S);
if(S[0] == 'C'){
scanf("%d%d",&x,&y);
w[x] =y;
memset(v[x],0,sizeof v[x]);
v[x][y] = 1;
FWT(v[x],1);
if(isr(x) && fa[x]) upd2(x,fa[x],-1);
upd(x);
if(isr(x) && fa[x]) upd2(x,fa[x],1);
for(x=fa[x];x;x=fa[x]){
if(isr(x) && fa[x]) upd2(x,fa[x],-1);
upd(x);
if(isr(x) && fa[x]) upd2(x,fa[x],1);
}
}
else{
scanf("%d",&x);
for(int i=0;i<m;i++) v[0][i] = su[rt][i];
FWT(v[0],-1);
printf("%d\n",(v[0][x]+mod)%mod);
}
}
}