还需要加强分析题目特殊性质,设计对应特殊算法,少想多写大力dfs剪枝不要管MLETLE直接上的能力

红包是一个有艺术细胞的男孩子。

红包由于NOI惨挂心情不好,暑假作业又多,于是他开始在作业本上涂鸦。

一开始,他在纸上画了一棵 nn 个节点的树。但是他觉得这样的画太简单了,体现不出他高超的绘画功底,于是他又额外画上了 kk 条边。

然而他觉得这样画面太复杂,于是想删去一些边使得这个无向图仍然是连通的。

请帮红包求出删边的方案数。两个方案被认为是不同的当且仅当存在一条边在其中一组中被删而另一组中没有。(什么边都不删也算一种方案)

输入格式

第一行两个整数,n,kn,k。保证 1≤n≤105,k≥01≤n≤105,k≥0。

接下来 n−1n−1 行,描述了红包最开始画的那颗树。每行两个整数 v,uv,u 表示 vv 和 uu 之间有一条无向边。

接下来 kk 行,描述了红包后来加的边。每行两个整数 v,uv,u 表示红包在 vv 和 uu 之间又加上了一条边。数据保证树中原有的边不会被再添加一次且 v≠uv≠u。

保证 1≤v,u≤n1≤v,u≤n。

输出格式

一个整数,表示方案数。你只用输出答案对 998244353998244353(7×17×223+17×17×223+1,一个质数)取模后的值。


题目分析

关于离线维护动态图连通性有一种常见套路:处理出原图的一颗dfs树,再为每一条非树边随机分配一个权值,剩下的树边权值就是所有经过它的非树边权值异或和。那么选出的边集对原图连通性没有影响当且仅当该边集的权值两两线性无关。

之前做过一题的套路就是这样的:【思维题 集合hash 树上差分】11.5撸树

关于这个随机化算法的证明,网上找到两篇高质量的证明 “图不连通 iff 删掉边集的权值线性相关”,

  1. 杜教的Dzy loves Chinese证明
  2. bzoj3569 DZY Loves Chinese II 正确性证明

对于这题,首先注意到k不大,那么就不需要常规做法的双哈希pair,而是直接将第i条非树边权值设为$2^{i-1}$.这样一来就能够在保证正确性的前提下减少常数。第二,如何求一个集合的线性无关子集个数?注意到这里的线性无关子集大小与集合元素种类都是和k同阶的。然后就可以用 算法七 的暴力dfs寻找线性无关子集数量,而因为“线性无关”这道剪枝“十分有力”,所以uoj榜上这个做法吊打标算……

 #include<bits/stdc++.h>
#define MO 998244353
typedef unsigned long long ull;
const int maxn = ;
const int maxm = ; struct Edge
{
int v,id;
Edge(int a=, int b=):v(a),id(b) {}
}edges[maxm];
struct node
{
ull val,cnt;
}a[maxm];
struct LinearBasis
{
ull a[];
bool insert(ull x)
{
for (int i=,chk=; i>=&&!chk; i--)
if ((x>>i)&){
if (a[i]) x ^= a[i];
else a[i] = x, chk = true;
}
return x > ;
}
};
int n,k,m,cnt,u[],v[];
int edgeTot,head[maxn],nxt[maxm];
ull eval[maxm],enod[maxn];
long long ans; int read()
{
char ch = getchar();
int num = , fl = ;
for (; !isdigit(ch); ch=getchar())
if (ch=='-') fl = -;
for (; isdigit(ch); ch=getchar())
num = (num<<)+(num<<)+ch-;
return num*fl;
}
void addedge(int u, int v, int id)
{
edges[++edgeTot] = Edge(v, id), nxt[edgeTot] = head[u], head[u] = edgeTot;
edges[++edgeTot] = Edge(u, id), nxt[edgeTot] = head[v], head[v] = edgeTot;
}
void color(int x, int fa)
{
for (int i=head[x]; i!=-; i=nxt[i])
{
int v = edges[i].v, id = edges[i].id;
if (v==fa) continue;
color(v, x), enod[x] = enod[x]^enod[v], eval[id] = enod[v];
}
}
void dfs(int x, LinearBasis s, int c)
{
if (x==cnt+) ans = (ans+c)%MO;
else{
dfs(x+, s, c);
if (s.insert(a[x].val))
dfs(x+, s, 1ll*c*a[x].cnt%MO);
}
}
int main()
{
memset(head, -, sizeof head);
n = read(), k = read();
for (int i=; i<n; i++)
addedge(read(), read(), i);
for (int i=; i<=k; i++)
u[i] = read(), v[i] = read(), eval[i+n-] = (ull)1ll<<i,
enod[u[i]] = enod[u[i]]^eval[i+n-], enod[v[i]] = enod[v[i]]^eval[i+n-];
color(, );
m = n+k-;
std::sort(eval+, eval+m+);
for (int i=,j=; i<=m; i=j)
if (eval[i]){
for (j=i; eval[j]==eval[i]&&j<=m; j++);
a[++cnt].val = eval[i], a[cnt].cnt = j-i;
}else ++j;
dfs(, LinearBasis(), );
printf("%lld\n",ans);
return ;
}

END

【线性基 集合hash】uoj#138. 【UER #3】开学前的涂鸦的更多相关文章

  1. UOJ #138. 【UER #3】开学前的涂鸦

    Description 红包是一个有艺术细胞的男孩子. 红包由于NOI惨挂心情不好,暑假作业又多,于是他开始在作业本上涂鸦. 一开始,他在纸上画了一棵 n 个节点的树.但是他觉得这样的画太简单了,体现 ...

  2. bzoj4568: [Scoi2016]幸运数字(LCA+线性基)

    4568: [Scoi2016]幸运数字 题目:传送门 题解: 好题!!! 之前就看过,当时说是要用线性基...就没学 填坑填坑: %%%线性基 && 神犇 主要还是对于线性基的运用和 ...

  3. [CQOI2013]新Nim游戏(博弈论,线性基)

    [CQOI2013]新Nim游戏 题目描述 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴.可以只拿一根 ...

  4. HDU - 3949 :XOR(线性基,所有集合的不同异或和中,求从小到大第K个)

    XOR is a kind of bit operator, we define that as follow: for two binary base number A and B, let C=A ...

  5. uoj#36. 【清华集训2014】玛里苟斯(线性基+概率期望)

    传送门 为啥在我看来完全不知道为什么的在大佬们看来全都是显然-- 考虑\(k=1\)的情况,如果序列中有某一个\(a_j\)的第\(i\)位为\(1\),那么\(x\)的第\(i\)位为\(1\)的概 ...

  6. UOJ #36 -【清华集训2014】玛里苟斯(线性基+暴搜)

    UOJ 题面传送门 看到 \(k\) 次方的期望可以很自然地想到利用低次方和维护高次方和的套路进行处理,不过.由于这里的 \(k\) 达到 \(5\),直接这么处理一来繁琐,二来会爆 long lon ...

  7. UOJ#36. 【清华集训2014】玛里苟斯 线性基

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ36.html 题解 按照 $k$ 分类讨论: k=1 : 我们考虑每一位的贡献.若有至少一个数第 $i$ ...

  8. BZOJ.3811.玛里苟斯(线性基)

    BZOJ UOJ 感觉网上大部分题解对我这种数学基础差的人来说十分不友好...(虽然理解后也觉得没有那么难) 结合两篇写的比较好的详细写一写.如果有错要指出啊QAQ https://blog.csdn ...

  9. Xor && 线性基练习

    #include <cstdio> #include <cstring> ; ; int cnt,Ans,b,x,n; inline int Max(int x,int y) ...

随机推荐

  1. gulp的watch记事本

    let gulp=require('gulp'), nodemon=require('gulp-nodemon'), browser=require('browser-sync'); let relo ...

  2. UVa 10256(凸包、线段交、点在多边形内)

    要点 红蓝点分别求凸包显然 判断两凸包是否相交方法:所有红点不在蓝凸包内,反之亦然:所有红凸包线不与蓝凸包线相交,反之亦然. 书上让特判一下凸包退化成点或线段的情况,为什么我感觉代码仓库的代码并没特判 ...

  3. oracle(三)

    /****************************表空间 start****************************/ --表空间的作用 /** 1.决定数据库实体的空间分配 2.设置 ...

  4. 开元java开发工具

    开元java开发工具 http://www.hutool.cn/

  5. Chapter13

    package scala /** * Created by EX-CHENZECHAO001 on 2018-04-04. */class Chapter13 { // 13 集合 // 所有的集合 ...

  6. Windows 命令行基础(博主推荐)

    不多说,直接上干货! 见 https://blog.henix.info/blog/windows-cmdbasic/

  7. Hive项目实战:用Hive分析“余额宝”躺着赚大钱背后的逻辑

    一.项目背景 前两年,支付宝推出的“余额宝”赚尽无数人的眼球,同时也吸引的大量的小额资金进入.“余额宝”把用户的散钱利息提高到了年化收益率4.0%左右,比起银行活期存储存款0.3%左右高出太多了,也正 ...

  8. maven安装,使用说明,及maven Repository如何使用.

    maven的使用方法总结一下 1.首先去apache官网下载maven, http://maven.apache.org/download.cgi2.如果是windows系统,选择 apache-ma ...

  9. GCC的内存边界对齐

      GCC有三种影响内存对齐的开关:           首先是命令行参数 –fpack_struct=n (n只可以是1,2,4,8等2的幂,而且要小于平台默认的对齐字节数,否则不会生效)      ...

  10. sublime 常用快捷键(转)

    Sublime text 3是码农最喜欢的代码编辑器,每天和代码打交道,必先利其器,掌握基本的代码编辑器的快捷键,能让你打码更有效率.刚开始可能有些生疏,只要花一两个星期坚持使用并熟悉这些常用的快捷键 ...