题目描述

从前有一名毒瘤。

毒瘤最近发现了量产毒瘤题的奥秘。考虑如下类型的数据结构题:给出一个数组,要求支持若干种奇奇怪怪的修改操作(例如给一个区间内的数同时加上 ccc,或者将一个区间内的数同时开平方根),并且支持询问区间的和。毒瘤考虑了 nnn 个这样的修改操作,并将它们编号为 1…n1 \ldots n1…n。当毒瘤要出数据结构题的时候,他就将这些修改操作中选若干个出来,然后出成一道题。

当然了,这样出的题有可能不可做。通过精妙的数学推理,毒瘤揭露了这些修改操作之间的关系:有 mmm 对「互相排斥」的修改操作,第 iii 对是第 uiu_iui​ 个操作和第 viv_ivi​ 个操作。当一道题中同时含有 uiu_iui​ 和 viv_ivi​ 这两个操作时,这道题就会变得不可做。另一方面,当一道题中不包含任何「互相排斥」的操作时,这个题就是可做的。此外,毒瘤还发现了一个规律:m−nm − nm−n 是一个很小的数字(参见「数据范围」中的说明),且任意两个修改操作都是连通的。两个修改操作 a,ba, ba,b 是连通的,当且仅当存在若干操作 t0,t1,...,tlt_0, t_1, ... , t_lt0​,t1​,...,tl​,使得 t0=a,tl=bt_0 = a,t_l = bt0​=a,tl​=b,且对任意 1≤i≤l1 \le i \le l1≤i≤l,ti−1t_{i−1}ti−1​ 和 tit_iti​ 都是「互相排斥」的修改操作。

一对「互相排斥」的修改操作称为互斥对。现在毒瘤想知道,给定值 nnn 和 mmm 个互斥对,他一共能出出多少道可做的不同的数据结构题。两个数据结构题是不同的,当且仅当其中某个操作出现在了其中一个题中,但是没有出现在另一个题中。

题解

为什么看到的题解都是虚树啊?这里介绍一个 ddp\text{ddp}ddp 做法。

如果 m=n−1m=n-1m=n−1 的话,那就是简单 dp\text{dp}dp : f[u][0/1]f[u][0/1]f[u][0/1] 表示 uuu 这个点选/不选的方案数,转移显然。

那现在如果 n≤mn \le mn≤m 的话,由于 m−n+1m-n+1m−n+1 不大所以我们只要减掉不合法情况即可,容易想到容斥。即枚举状态然后把状态中为 111 的边的两端强制选(即 f[u][0]=0f[u][0]=0f[u][0]=0 ),然后再做 dp\text{dp}dp 即可,可是这样是 O(2m−n+1n)O(2^{m-n+1}n)O(2m−n+1n) 的过不去。然后我们发现转移可以写成矩阵的形式,于是就可以用树剖+线段树维护矩阵乘即可,效率 O(2m−n+1log2n+n)O(2^{m-n+1}log^2n+n)O(2m−n+1log2n+n) 。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+15,M=N<<1,P=998244353;
int n,m,hd[N],V[M],nx[M],t=1,top[N],sz[N],dp[N],fa[N];
int son[N],f[N][2],h[N],df[N],id[N],b[15],g[N][2],s;
vector<int>G[N][2];bool vis[N];
struct O{int p[2][2];}W,a[N<<2];
int X(int x){return x>=P?x-P:x;}
int K(int x,int y){int z=1;for (;y;y>>=1,x=1ll*x*x%P)if (y&1) z=1ll*z*x%P;return z;
}
O Mul(O A,O B){for (int i=0;i<2;i++)for (int j=0;j<2;j++){W.p[i][j]=0;for (int k=0;k<2;k++)W.p[i][j]=X(W.p[i][j]+1ll*A.p[k][j]*B.p[i][k]%P);}return W;
}
void add(int u,int v){nx[++t]=hd[u];V[hd[u]=t]=v;
}
void dfs(int u,int fr){dp[u]=dp[fa[u]=fr]+1;sz[u]=1;vis[u]=1;for (int v,i=hd[u];i;i=nx[i]){if (vis[v=V[i]]) continue;dfs(v,u);sz[u]+=sz[v];if (sz[v]>sz[son[u]]) son[u]=v;}
}
void Dfs(int u,int tp){top[u]=tp;h[u]=df[id[u]=++t]=u;if (son[u]) Dfs(son[u],tp),h[u]=h[son[u]];for (int i=hd[u];i;i=nx[i])if (V[i]!=son[u] && fa[V[i]]==u)Dfs(V[i],V[i]);
}
void Dp(int u){f[u][0]=f[u][1]=g[u][0]=g[u][1]=1;for (int v,i=hd[u];i;i=nx[i])if (fa[v=V[i]]==u) Dp(v),f[u][0]=1ll*f[u][0]*(f[v][0]+f[v][1])%P,f[u][1]=1ll*f[u][1]*f[v][0]%P;
}
#define Ls k<<1
#define Rs k<<1|1
#define mid ((l+r)>>1)
void build(int k,int l,int r){if (l==r){int u=df[l];for (int i=hd[u];i;i=nx[i])if (V[i]!=son[u] && fa[V[i]]==u)g[u][0]=1ll*g[u][0]*(f[V[i]][0]+f[V[i]][1])%P,g[u][1]=1ll*g[u][1]*f[V[i]][0]%P;a[k]=(O){g[u][0],g[u][0],g[u][1],0};return;}build(Ls,l,mid);build(Rs,mid+1,r);a[k]=Mul(a[Rs],a[Ls]);
}
O qry(int k,int l,int r,int L,int R){if (L<=l && r<=R) return a[k];if (mid<L) return qry(Rs,mid+1,r,L,R);if (mid>=R) return qry(Ls,l,mid,L,R);return Mul(qry(Rs,mid+1,r,L,R),qry(Ls,l,mid,L,R));
}
void upd(int k,int l,int r,int x,int v0,int v1){if (l==r){a[k]=(O){v0,v0,v1,0};return;}if (mid>=x) upd(Ls,l,mid,x,v0,v1);else upd(Rs,mid+1,r,x,v0,v1);a[k]=Mul(a[Rs],a[Ls]);}
void del(int x,int o){O v;int v0,v1,u;while(x!=1){v=qry(1,1,n,id[x],id[h[x]]);v0=v.p[0][0],v1=v.p[1][0],u=fa[x];if (!o) G[u][0].push_back(g[u][0]),G[u][1].push_back(g[u][1]);g[u][0]=1ll*g[u][0]*K(X(v0+v1),P-2)%P;g[u][1]=1ll*g[u][1]*K(v0,P-2)%P;x=top[u];}
}
void ins(int x,int o){O v;int v0,v1,u;while(x!=1){v=qry(1,1,n,id[x],id[h[x]]);v0=v.p[0][0],v1=v.p[1][0],u=fa[x];if (o){int z=G[u][0].size();g[u][0]=G[u][0][z-1];G[u][0].pop_back();g[u][1]=G[u][1][z-1];G[u][1].pop_back();}elseg[u][0]=1ll*g[u][0]*(v0+v1)%P,g[u][1]=1ll*g[u][1]*v0%P;upd(1,1,n,id[u],g[u][0],g[u][1]);x=top[u];}
}
int main(){cin>>n>>m;for (int u,v,i=1;i<=m;i++)scanf("%d%d",&u,&v),add(u,v),add(v,u);t=0;dfs(1,0);Dfs(1,1);Dp(1);build(1,1,n);t=0;for (int u,v,i=1;i<=m;i++){u=V[i<<1],v=V[i<<1|1];if (dp[u]>dp[v]) swap(u,v);if (fa[v]!=u) b[t++]=i;}for (int F,i=(1<<t)-1;~i;i--){F=1;for (int j=0;j<t;j++)if ((i>>j)&1){F=P-F;for (int u,k=0;k<2;k++){u=V[b[j]<<1|k];del(top[u],0);G[u][0].push_back(g[u][0]);G[u][1].push_back(g[u][1]);upd(1,1,n,id[u],g[u][0]=0,g[u][1]);ins(top[u],0);}}O v=qry(1,1,n,1,id[h[1]]);s=X(1ll*F*(v.p[0][0]+v.p[1][0])%P+s);for (int z,j=t-1;~j;j--)if ((i>>j)&1){F=P-F;for (int u,k=0;k<2;k++){u=V[b[j]<<1|k];del(top[u],1);z=G[u][0].size();g[u][0]=G[u][0][z-1];G[u][0].pop_back();g[u][1]=G[u][1][z-1];G[u][1].pop_back();upd(1,1,n,id[u],g[u][0],g[u][1]);ins(top[u],1);}}}cout<<s<<endl;return 0;
}

#3688. 毒瘤(duliu)相关推荐

  1. duliu——思维+线段树

    题目 [题目描述] 小 `D` 喜欢出毒瘤题毒人.当然,他的毒瘤更多体现在若干个难题组合在同一场比赛时. 小 `D` 脑中有 $n$ 个毒瘤题 idea,第 $i$ 个的毒值为$d_i$.当第 $i$ ...

  2. [BZOJ3337] ORZJRY I --块状链表大毒瘤

    link 题目大意:维护一个序列 支持: 1.单点插入 2.单点删除 3.区间翻转 4.区间旋转 5.区间加 6.区间赋值 7.询问区间和 8.询问区间极差 9.询问区间与给定某个数差值绝对值的最小值 ...

  3. TCP/IP中 3688端口是什么?

    原文英文:http://www.corrupteddatarecovery.com/Port/3688udp-Port-Type-simple-push-s-simple-push-s.asp 翻译的 ...

  4. 10年读4个博士学位的“神之子”创办「莆田系」AI顶会,骗欧美学术精英,收报名费3688元...

    文末留言区送 6 本机械工业出版社赞助书籍 贾浩楠 发自 凹非寺 量子位 报道 | 公众号 QbitAI 机器人领域顶会ICRA 2021,将于明年7月19-21日在奥地利维也纳举办,报名注册费用45 ...

  5. 毒瘤题No.006-byFHS

    毒瘤题No.006-byFHS 题目背景 暂无 题目描述 给你一个无向图,求最少用多少棵树来覆盖这个图上的所有边 输入格式 第1行:两个数\(n,m\),表示有\(n\)个点,\(m\)条边 接下来\ ...

  6. 约会安排 (区间合并)毒瘤题

    约会安排 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submi ...

  7. 印度裔“教授”奇葩操作!办假AI顶会,骗欧美学术精英,收报名费3688元

    贾浩楠 发自 凹非寺 量子位 报道 | 公众号 QbitAI 机器人领域顶会ICRA 2021,将于明年7月19-21日在奥地利维也纳举办,报名注册费用450欧元--折合人民币约3688元. 目前组委 ...

  8. 【UOJ#67】新年的毒瘤 Tarjan 割点

    #67. 新年的毒瘤 UOJ直接黏贴会炸...    还是戳这里吧: http://uoj.ac/problem/67#tab-statement Solution 看到这题的标签就进来看了一眼. 想 ...

  9. Potato的暑期训练day#1题解 ——毒瘤构造

    Potato的暑期训练day#1 --毒瘤构造 题目链接: A.https://vjudge.net/problem/HDU-1214 B.https://vjudge.net/problem/Cod ...

  10. 百度广告点击软件_结束了,百度 “毒瘤” 广告!

     " 通过本文,你可以获取一款上网必备的插件,让你摆脱各种"毒瘤"广告." 大家天天逛网页,最恼人的也就是广告了吧.尤其是百度搜索时. 01 - 毒瘤广告有多愁 ...

最新文章

  1. P5904-[POI2014]HOT-Hotels加强版【长链剖分,dp】
  2. 微信超赞新功能上线,终于知道钱花哪儿了
  3. mediawiki 编辑php代码,mediawiki_1.25配置wikieditor编辑器
  4. java 格式化日期(DateFormat)
  5. 如何将python数据输入到excel中_如何使用python将大量数据导出到Excel中的小技巧之一...
  6. js调整数组某些元素到指定位置顺序_如何在JS数组特定索引处指定位置插入元素?...
  7. 【vuejs面试题】务必熟知的vuejs面试题「务必收藏」
  8. java基础 泛型类的定义
  9. vp230引脚功能_SN65HVD230:具有待机模式的 3.3V CAN 收发器
  10. linux卸载cognos,在Linux上实战安装Cognos
  11. windbg分析BSOD dump文件实战
  12. Python实战|「甜点消消」游戏数据分析过程
  13. 高德地图开放平台的使用
  14. [笔记] 数据结构二刷【第一篇:线性表·栈·队列·递归】
  15. CodeForces - [ACM-ICPC Jiaozuo Onsite A]Xu Xiake in Henan Province(模拟)
  16. 大数据_02【大数据基础知识】
  17. 【文档】Word如何将一个文档的样式复制到另一个文档中
  18. 【Hash篇】HashTab一款可扩展资源管理器的哈希校验软件
  19. day06三级缓存 二次采样
  20. 守望者的逃离(贪心,动态规划)

热门文章

  1. 今日恐慌与贪婪指数为14,恐慌程度与昨日持平
  2. pe版linux操作系统制作,制作Linux版PE系统
  3. DOS下常用命令介绍
  4. 揭开Docker的神秘面纱
  5. 新型穿墙监控雷达Range-R:让你的隐私无所遁形(转)
  6. 凯撒密码加密你的姓名拼音(c)
  7. java计算机毕业设计共享充电宝管理系统源码+mysql数据库+系统+lw文档+部署(2)
  8. Problem B 1076 素数
  9. 数据库事务ACID四大特性:原子性、一致性, 隔离性, 持久性
  10. 02读书笔记:《编码》-隐匿在计算机软硬件背后的语言(12-14章)