bzoj 4911: [Sdoi2017]切树游戏
考虑维护原树的lct,在上面dp,由于dp方程特殊,均为异或卷积或加法,计算中可以只使用fwt后的序列
v[w]表示联通子树的最浅点为w,且不选w的splay子树中的点
l[w]表示联通子树的最浅点在w的lct子树中,且选w的splay子树中极左点(w的splay子树为{w}+{u的splay子树,满足u==ch[w][0]||u==ch[w][1]})
r[w]表示联通子树的最浅点在w的lct子树中,且选w的splay子树中极右点
lr[w]表示联通子树的最浅点为w,且选w的splay子树中所有的点
s[w]表示联通子树的最浅点在w的lct子树中(w的lct子树为{w}+{u的lct子树,满足fa[u]==w})
ss[w]表示联通子树的最浅点在w的lct子树中,且不选w
时间复杂度O((n+q)mlogm),由于dp方程复杂以及lct自带的常数,总体常数较大
- #include<bits/stdc++.h>
- #define fm(i) for(int i=0;i<m;++i)
- typedef int arr[];
- const int N=,P=;
- int n,m,v0[N],ivs[],*iv=ivs+P+;
- arr x0[],ans,tmp;
- std::vector<int>e[N];
- struct node{
- node*c[],*f;
- arr v,vt,l,r,lr,s,ss;
- bool nrt();
- void up();
- void setrc(node*w);
- }ns[N],*nil=ns,*rt=ns+;
- void cpy(int*a,int*b){memcpy(a,b,sizeof(int)*m);}
- bool node::nrt(){return this==f->c[]||this==f->c[];}
- void node::up(){
- fm(i){
- int vi=vt[i]?:v[i];
- int vc0lr=vi*c[]->lr[i]%P;
- int vc0r=vi*c[]->r[i]%P;
- l[i]=(vc0lr*c[]->l[i]+c[]->l[i])%P;
- r[i]=(vc0r*c[]->lr[i]+c[]->r[i])%P;
- lr[i]=vc0lr*c[]->lr[i]%P;
- s[i]=(vc0r*c[]->l[i]+ss[i])%P;
- }
- }
- void mul(int*v1,int*t,int*v2){fm(i)v2[i]?v1[i]=v1[i]*v2[i]%P:++t[i];}
- void div(int*v1,int*t,int*v2){fm(i)v2[i]?v1[i]=v1[i]*iv[v2[i]]%P:--t[i];}
- void node::setrc(node*w){
- if(c[]!=nil)mul(v,vt,c[]->l);
- c[]=w;
- if(c[]!=nil)div(v,vt,c[]->l);
- up();
- }
- void rot(node*w){
- node*f=w->f,*g=f->f;
- int d=w==f->c[];
- if(f->nrt())g->c[g->c[]==f]=w;
- w->f=g;
- (f->c[d]=w->c[d^])->f=f;
- (w->c[d^]=f)->f=w;
- fm(i){
- int x=f->ss[i],y=f->c[d]->s[i];
- f->ss[i]=(x-w->s[i]+y)%P;
- w->s[i]=f->s[i];
- w->ss[i]-=y;
- }
- f->up();
- fm(i)w->ss[i]=(w->ss[i]+f->s[i])%P;
- }
- void sp(node*w){
- if(!w->nrt())return;
- do{
- node*f=w->f;
- if(f->nrt())rot((f->c[]==w)==(f->f->c[]==f)?f:w);
- rot(w);
- }while(w->nrt());
- w->up();
- }
- void acs(node*x){
- rt=x;
- for(node*y=nil;x!=nil;sp(x),x->setrc(y),y=x,x=x->f);
- sp(rt);
- }
- void dfs(int w,int pa){
- for(int i=;i<e[w].size();++i){
- int u=e[w][i];
- if(u!=pa){
- dfs(u,w);
- ns[u].f=ns+w;
- mul(ns[w].v,ns[w].vt,ns[u].l);
- fm(j)ns[w].ss[j]+=ns[u].s[j];
- }
- }
- ns[w].up();
- }
- void dwt(int*a){
- for(int i=;i<m;i<<=){
- for(int j=;j<m;j+=i<<){
- int*b=a+j,*c=b+i;
- for(int k=;k<i;++k){
- int x=b[k],y=c[k];
- b[k]=x+y;
- c[k]=x-y;
- }
- }
- }
- fm(i)a[i]%=P;
- }
- char buf[],*ptr=buf;
- int _(){
- int x=;
- while(*ptr<)++ptr;
- while(*ptr>)x=x*+*ptr++-;
- return x;
- }
- int main(){
- fread(buf,,sizeof(buf),stdin);
- n=_();m=_();
- for(int i=;i<m;++i){
- x0[i][i]=;
- dwt(x0[i]);
- }
- iv[-P]=iv[]=;
- for(int i=;i<P;++i)iv[i-P]=iv[i]=(P-P/i)*iv[P%i]%P;
- for(int i=;i<=n;++i)ns[i]=(node){nil,nil,nil};
- cpy(nil->l,x0[]);
- cpy(nil->r,x0[]);
- cpy(nil->lr,x0[]);
- for(int i=;i<=n;++i){
- v0[i]=_();
- cpy(ns[i].v,x0[v0[i]]);
- }
- for(int i=,a,b;i<n;++i){
- a=_(),b=_();
- e[a].push_back(b);
- e[b].push_back(a);
- }
- dfs(,);
- for(int q=_(),ed=;q;--q){
- if(_()==){
- if(ed){
- cpy(ans,rt->s);
- dwt(ans);
- ed=;
- }
- printf("%d\n",(ans[_()]*iv[m]%P+P)%P);
- }else{
- ed=;
- int w=_(),x=_();
- acs(ns+w);
- int*v1=x0[v0[w]],*v2=x0[x];
- fm(i)rt->v[i]=rt->v[i]*v1[i][iv]%P*v2[i]%P;
- fm(i)ans[i]=rt->vt[i]?:rt->v[i];
- dwt(ans);
- v0[w]=x;
- rt->up();
- }
- }
- return ;
- }
由于树形态不改变,也可以建一棵深度不超过logn+O(1)的静态lct,可以明显减小常数
- #include<bits/stdc++.h>
- #define fm(i) for(int i=0;i<m;++i)
- typedef int arr[];
- const int N=,P=;
- int n,m,v0[N],ivs[],*iv=ivs+P+;
- arr x0[],ans,tmp;
- std::vector<int>e[N];
- struct node{
- node*c[],*f;
- arr v,vt,l,r,lr,s,ss;
- bool isrt();
- void up();
- }ns[N],*nil=ns,*rt;
- bool node::isrt(){return this!=f->c[]&&this!=f->c[];}
- void cpy(int*a,int*b){memcpy(a,b,sizeof(int)*m);}
- void node::up(){
- fm(i){
- int vi=vt[i]?:v[i];
- int vc0lr=vi*c[]->lr[i]%P;
- int vc0r=vi*c[]->r[i]%P;
- l[i]=(vc0lr*c[]->l[i]+c[]->l[i])%P;
- r[i]=(vc0r*c[]->lr[i]+c[]->r[i])%P;
- lr[i]=vc0lr*c[]->lr[i]%P;
- s[i]=(vc0r*c[]->l[i]+ss[i])%P;
- }
- }
- void mul(int*v1,int*t,int*v2){fm(i)v2[i]?v1[i]=v1[i]*v2[i]%P:++t[i];}
- void div(int*v1,int*t,int*v2){fm(i)v2[i]?v1[i]=v1[i]*iv[v2[i]]%P:--t[i];}
- int fa[N],sz[N],son[N],dep[N],top[N],ws[N],wp;
- void f1(int w,int pa){
- dep[w]=dep[fa[w]=pa]+(sz[w]=);
- for(int i=;i<e[w].size();++i){
- int u=e[w][i];
- if(u!=pa){
- f1(u,w);
- sz[w]+=sz[u];
- if(sz[u]>sz[son[w]])son[w]=u;
- }
- }
- ns[w].up();
- }
- node*build(int L,int R,node*f){
- if(L>R)return nil;
- int L0=L,R0=R;
- for(int M,s0=ws[L][sz]+ws[R+][sz];L<R;ws[M=L+R+>>][sz]*<s0?R=M-:L=M);
- node*w=ns+ws[L];
- w->c[]=build(L0,L-,w);
- w->c[]=build(L+,R0,w);
- w->f=f;
- w->up();
- if(f!=nil){
- fm(i)f->ss[i]+=w->s[i];
- if(L0==&&R0==wp)mul(f->v,f->vt,w->l);
- }
- return w;
- }
- void f2(int w,int tp){
- top[w]=tp;
- for(int i=;i<e[w].size();++i){
- int u=e[w][i];
- if(u!=fa[w]&&u!=son[w])f2(u,u);
- }
- if(son[w])f2(son[w],tp);
- else{
- wp=;
- for(int a=tp;a;a=son[a])ws[++wp]=a;
- ws[wp+]=;
- rt=build(,wp,ns+fa[tp]);
- }
- }
- void dwt(int*a){
- for(int i=;i<m;i<<=){
- for(int j=;j<m;j+=i<<){
- int*b=a+j,*c=b+i;
- for(int k=;k<i;++k){
- int x=b[k],y=c[k];
- b[k]=x+y;
- c[k]=x-y;
- }
- }
- }
- fm(i)a[i]%=P;
- }
- char buf[],*ptr=buf;
- int _(){
- int x=;
- while(*ptr<)++ptr;
- while(*ptr>)x=x*+*ptr++-;
- return x;
- }
- int main(){
- fread(buf,,sizeof(buf),stdin);
- n=_();m=_();
- for(int i=;i<m;++i){
- x0[i][i]=;
- dwt(x0[i]);
- }
- iv[-P]=iv[]=;
- for(int i=;i<P;++i)iv[i-P]=iv[i]=(P-P/i)*iv[P%i]%P;
- for(int i=;i<=n;++i)ns[i]=(node){nil,nil,nil};
- cpy(nil->l,x0[]);
- cpy(nil->r,x0[]);
- cpy(nil->lr,x0[]);
- for(int i=;i<=n;++i){
- v0[i]=_();
- cpy(ns[i].v,x0[v0[i]]);
- }
- for(int i=,a,b;i<n;++i){
- a=_(),b=_();
- e[a].push_back(b);
- e[b].push_back(a);
- }
- f1(,);f2(,);
- for(int q=_(),ed=;q;--q){
- if(_()==){
- if(ed){
- cpy(ans,rt->s);
- dwt(ans);
- ed=;
- }
- printf("%d\n",(ans[_()]*iv[m]%P+P)%P);
- }else{
- ed=;
- int w=_(),x=_(),stp=;
- node*_w=ns+w,*stk[];
- for(node*a=_w;a!=nil;stk[++stp]=a,a=a->f);
- for(int i=stp;i>;--i){
- int*v1=stk[i]->ss,*v2=stk[i-]->s;
- fm(j)v1[j]-=v2[j];
- if(stk[i-]->isrt())div(stk[i]->v,stk[i]->vt,stk[i-]->l);
- }
- int*v1=x0[v0[w]],*v2=x0[x];
- fm(i)_w->v[i]=_w->v[i]*v1[i][iv]%P*v2[i]%P;
- _w->up();
- for(int i=;i<=stp;++i){
- int*v1=stk[i]->ss,*v2=stk[i-]->s;
- fm(j)v1[j]=(v1[j]+v2[j])%P;
- if(stk[i-]->isrt())mul(stk[i]->v,stk[i]->vt,stk[i-]->l);
- stk[i]->up();
- }
- v0[w]=x;
- }
- }
- return ;
- }
bzoj 4911: [Sdoi2017]切树游戏的更多相关文章
- 【BZOJ4911】[SDOI2017]切树游戏(动态dp,FWT)
[BZOJ4911][SDOI2017]切树游戏(动态dp,FWT) 题面 BZOJ 洛谷 LOJ 题解 首先考虑如何暴力\(dp\),设\(f[i][S]\)表示当前以\(i\)节点为根节点,联通子 ...
- BZOJ4911: [Sdoi2017]切树游戏
BZOJ 4911 切树游戏 重构了三次.jpg 每次都把这个问题想简单了.jpg 果然我还是太菜了.jpg 这种题的题解可以一眼秒掉了,FWT+动态DP简直是裸的一批... 那么接下来,考虑如何维护 ...
- LG3781 [SDOI2017]切树游戏
题意 题目描述 小Q是一个热爱学习的人,他经常去维基百科学习计算机科学. 就在刚才,小Q认真地学习了一系列位运算符,其中按位异或的运算符\(\oplus\)对他影响很大.按位异或的运算符是双目运算符. ...
- LOJ2269 [SDOI2017] 切树游戏 【FWT】【动态DP】【树链剖分】【线段树】
题目分析: 好题.本来是一道好的非套路题,但是不凑巧的是当年有一位国家集训队员正好介绍了这个算法. 首先考虑静态的情况.这个的DP方程非常容易写出来. 接着可以注意到对于异或结果的计数可以看成一个FW ...
- [SDOI2017]切树游戏
题目 二轮毒瘤题啊 辣鸡洛谷竟然有卡树剖的数据 还是\(loj\)可爱 首先这道题没有带修,设\(dp_{i,j}\)表示以\(i\)为最高点的连通块有多少个异或和为\(j\),\(g_{i,j}=\ ...
- 洛谷 P3781 - [SDOI2017]切树游戏(动态 DP+FWT)
洛谷题面传送门 SDOI 2017 R2 D1 T3,nb tea %%% 讲个笑话,最近我在学动态 dp,wjz 在学 FWT,而我们刚好在同一天做到了这道题,而这道题刚好又是 FWT+动态 dp ...
- 【LOJ】#2269. 「SDOI2017」切树游戏
题解 把所有的数组一开始就FWT好然后再IFWT回去可以减小常数 从13s跑到0.7s-- 可以参照immortalCO的论文,感受一下毒瘤的动态动态DP 就是用数据结构维护线性递推的矩阵的乘积 由于 ...
- 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}= ...
随机推荐
- 练习vue(用户管理)1
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- Linux内核分析-使用gdb跟踪调试内核从start_kernel到init进程启动
姓名:江军 ID:fuchen1994 实验日期:2016.3.13 实验指导 使用实验楼的虚拟机打开shell cd LinuxKernel/ qemu -kernel linux-3.18.6/a ...
- python 枚举Enum类的使用
1. 枚举的定义 首先,定义枚举要导入enum模块. 枚举定义用class关键字,继承Enum类. 示例代码: from enum import Enum class Color(Enum): red ...
- juery 安全加固 集合
来源 jquery升级坑 2 3 4 5 版本 相关源码分享 新建document jquery ajax使用说明 最近在iteye的新闻中看到jQuery已经更新到了1.6.1. 和 ...
- tmux安装与使用
安装 用法 重点 一prefix前缀键 二window和pane的区分 tmux 按照官方给出的介绍是:终端复用工具.说白了就是可以仅仅在开启一个终端的情况下同时处理多个任务. 比如下面我设置的这样一 ...
- iOS被开发者遗忘在角落的NSException-其实它很强大
NSException是什么? 最熟悉的陌生人,这是我对NSException的概述,为什么这么说呢?其实很多开发者接触到NSException的频率非常频繁,但很多人都不知道什么是NSExcepti ...
- tensorflow读取训练数据方法
1. 预加载数据 Preloaded data # coding: utf-8 import tensorflow as tf # 设计Graph x1 = tf.constant([2, 3, 4] ...
- ubuntu16.04 下 NVIDIA GTX1050ti 显卡驱动 PPA安装
本文参考资料链接: http://blog.csdn.net/10km/article/details/61191230 前几天在京东商城上花了6999元买了台笔记本(惠普(HP)暗影精灵II代Pro ...
- Oracle Tuning (Oracle 性能调整)的一些总结
Oracle Tuning (Oracle 性能调整)的一些总结 Oracle Tuning (Oracle 性能调整)的一些总结关于Oracle的性能调整,一般包括两个方面,一是指Oracle数据库 ...
- 【图像处理】Haar-like特征
特征提取的原理.代码等: 如果是白黑白,是减去一个黑的还是2个黑的,网上有不同的说法:应该需要看原论文了. 论文原文 The sum of the pixels which lie within th ...