[鏈分治 重鏈剖分 FWT] BZOJ 4911 [Sdoi2017]切樹遊戲
阿新 • • 發佈:2019-02-04
我鏈分治是從immortalCO今年論文學來的
就是一個序列上能夠維護的東西,把他搬到重鏈上,先處理好兒子重鏈的答案,然後把對這條重鏈上的影響累加在這條重鏈上
修改就爬重鏈一路改上去
然後就是套路 FWT一下就能加和乘了
注意0沒有逆元
複雜度
rank1 開心 O(∩_∩)O~~
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10 +c-'0',c=nc()); x*=b;
}
inline void read(char &x){
for (x=nc();x!='Q' && x!='C';x=nc());
}
const int N=30005;
const int KK=128;
const int P=10007;
const int INV2=(P+1)>>1;
inline void FWT(int *a,int n,int r){
for (int i=1;i<n;i<<=1)
for (int j=0;j<n;j+=(i<<1))
for (int k=0;k<i;k++){
int x=a[j+k],y=a[j+k+i];
if (r) a[j+k]=(x+y)%P,a[j+k+i]=(x+P-y)%P;
else a[j+k]=(x+y)*INV2%P,a[j+k+i]=(x+P-y)*INV2%P;
}
}
int K,kx[KK][KK];
int inv[P];
inline void Pre(int n){
for (int i=0;i<n;i++)
kx[i][i]=1,FWT(kx[i],n,1);
inv[1]=1;
for (int i=2;i<P;i++)
inv[i]=(P-P/i)*inv[P%i]%P;
}
struct edge{
int u,v,next;
}G[N<<1];
int head[N],inum;
#define V G[p].v
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int fat[N],top[N],size[N];
int depth[N];
inline void dfs(int u,int fa){
fat[u]=fa; size[u]=1; depth[u]=depth[fa]+1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
dfs(V,u),size[u]+=size[V];
}
vector<int> p[N];
inline void find(int u,int fa,int z){
top[u]=z; p[z].pb(u);
int maxv=0,son=0;
for (int p=head[u];p;p=G[p].next)
if (V!=fa && size[V]>maxv)
maxv=size[son=V];
if (son) find(son,u,z);
for (int p=head[u];p;p=G[p].next)
if (V!=fa && V!=son)
find(V,u,V);
}
const int M=70005;
int ncnt,rt[N],pos[N];
int ps[M],ls[M],rs[M];
int sum[M][KK],lval[M][KK],rval[M][KK],val[M][KK];
inline void upd(int x){
int L=ls[x],R=rs[x];
for (int i=0;i<K;i++){
val[x][i]=(val[L][i]+val[R][i]+rval[L][i]*lval[R][i])%P;
lval[x][i]=(lval[L][i]+lval[R][i]*sum[L][i])%P;
rval[x][i]=(rval[R][i]+rval[L][i]*sum[R][i])%P;
sum[x][i]=sum[L][i]*sum[R][i]%P;
}
}
struct abcd{
int x,y;
abcd(){ }
abcd(int num){
if (num) x=num,y=0; else x=1,y=1;
}
abcd & operator *= (int a){
if (a==0) y++; else x=x*a%P;
return *this;
}
abcd & operator /= (int a){
if (a==0) y--; else x=x*inv[a]%P;
return *this;
}
int val(){
return y?0:x;
}
};
abcd base[N][KK];
inline void Build(int &x,int l,int r,int t){
x=++ncnt;
if (l==r){
for (int i=0;i<K;i++)
val[x][i]=lval[x][i]=rval[x][i]=sum[x][i]=base[p[t][l-1]][i].val();
pos[p[t][l-1]]=x;
return;
}
int mid=(l+r)>>1;
Build(ls[x],l,mid,t); Build(rs[x],mid+1,r,t);
upd(x); ps[ls[x]]=ps[rs[x]]=x;
}
int ans[KK],tmp[KK];
inline void Modify(int u){
int t=top[u];
if (fat[t])
for (int j=0;j<K;j++)
base[fat[t]][j]/=(lval[rt[t]][j]+kx[0][j])%P;
for (int j=0;j<K;j++)
ans[j]=(ans[j]+P-val[rt[t]][j])%P;
int x=pos[u];
for (int i=0;i<K;i++)
val[x][i]=lval[x][i]=rval[x][i]=sum[x][i]=base[u][i].val();
x=ps[x];
while (x)
upd(x),x=ps[x];
if (fat[t])
for (int j=0;j<K;j++)
base[fat[t]][j]*=(lval[rt[t]][j]+kx[0][j])%P;
for (int j=0;j<K;j++)
ans[j]=(ans[j]+val[rt[t]][j])%P;
}
int n,vv[N];
int lst[N],pnt;
inline bool cmp(int x,int y){
return depth[x]>depth[y];
}
int main(){
int x,y,Q; char order;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(K); int t=1; while (t<K) t<<=1; K=t;
Pre(K);
for (int i=1;i<=n;i++){
read(x); vv[i]=x;
for (int j=0;j<K;j++) base[i][j]=abcd(kx[x][j]);
}
for (int i=1;i<n;i++)
read(x),read(y),add(x,y,++inum),add(y,x,++inum);
dfs(1,0); find(1,0,1);
for (int i=1;i<=n;i++) if (top[i]==i) lst[++pnt]=i;
sort(lst+1,lst+pnt+1,cmp);
for (int i=1;i<=pnt;i++){
int x=lst[i];
Build(rt[x],1,p[x].size(),x);
if (fat[x]){
int f=fat[x];
for (int j=0;j<K;j++)
base[f][j]*=(lval[rt[x]][j]+kx[0][j])%P;
}
for (int j=0;j<K;j++)
ans[j]=(ans[j]+val[rt[x]][j])%P;
}
read(Q);
while (Q--){
read(order); read(x);
if (order=='C'){
read(y);
for (int j=0;j<K;j++)
base[x][j]/=kx[vv[x]][j];
vv[x]=y;
for (int j=0;j<K;j++)
base[x][j]*=kx[vv[x]][j];
while (x!=0)
Modify(x),x=fat[top[x]];
}else if (order=='Q'){
for (int j=0;j<K;j++) tmp[j]=ans[j];
FWT(tmp,K,0);
printf("%d\n",tmp[x]);
}
}
return 0;
}