[NOI2021 day1]轻重边(树链剖分),路径交点(矩阵行列式)

NOI 2021 day1

  • 轻重边
    • description
    • solution
    • code
  • 路径交点
    • description
    • solution
    • code

轻重边

description

solution

  • case=1~6

    把父亲和儿子的边转化为储存在儿子上的点

    建树,暴力爬lcalcalca,暴力修改,O(n2)O(n^2)O(n2)

  • case=A

    对于一条链的情况,每次修改重边就是一段区间,轻边只有两个端点相连的边

    同样的边化点,线性用线段树区间/单点修改,区间查询

  • case=B

    第二类操作询问只有一条边,考虑这条边怎么才可能是重边,显然就是两个点最后被经过的时间戳要一样

    树链剖分打时间戳

  • case=1~20

    正解其实就在case=B基础上,的确一条边如果是轻边当且仅当该边的两个端点所打时间戳不同

    树链剖分维护数颜色段的个数(轻边的数量),重边数量减一下就可以了

    最原始局面全都是轻边,所以初始化建树时就要给每个点打一个不同的时间戳

蒟蒻只想到所有到case=B的前70%70\%70%的部分分,实在没想到颜色段个数

code

#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define maxn 100005
#define lson num << 1
#define rson num << 1 | 1
struct node {int cnt, l, r, tag;
}t[maxn << 2];
vector < int > G[maxn];
int T, n, m, cnt;
int dep[maxn], son[maxn], top[maxn], dfn[maxn], f[maxn], siz[maxn];void dfs1( int u, int fa ) {dep[u] = dep[fa] + 1, f[u] = fa, siz[u] = 1;for( auto v : G[u] ) {if( v == fa ) continue;else dfs1( v, u );siz[u] += siz[v];if( siz[v] > siz[son[u]] )son[u] = v; }
}void dfs2( int u, int tt ) {top[u] = tt, dfn[u] = ++ cnt;if( son[u] ) dfs2( son[u], tt );else return;for( auto v : G[u] ) {if( v == f[u] || v == son[u] ) continue;else dfs2( v, v );}
}void pushdown( int num ) {if( ! t[num].tag ) return;t[lson].l = t[lson].r = t[lson].tag = t[num].tag;t[rson].l = t[rson].r = t[rson].tag = t[num].tag;t[lson].cnt = t[rson].cnt = 1;t[num].tag = 0;return;
}void build( int num, int l, int r ) {if( l == r ) {t[num].cnt = 1, t[num].l = t[num].r = l;return;}int mid = ( l + r ) >> 1;build( lson, l, mid );build( rson, mid + 1, r );t[num].l = t[lson].l, t[num].r = t[rson].r;t[num].cnt = t[lson].cnt + t[rson].cnt;t[num].tag = 0;
}void modify( int num, int l, int r, int L, int R, int id ) {if( R < l || r < L ) return;if( L <= l && r <= R ) {t[num].cnt = 1, t[num].l = t[num].r = t[num].tag = id;return;}pushdown( num );int mid = ( l + r ) >> 1;modify( lson, l, mid, L, R, id );modify( rson, mid + 1, r, L, R, id );t[num].l = t[lson].l, t[num].r = t[rson].r;t[num].cnt = t[lson].cnt + t[rson].cnt - ( t[lson].r == t[rson].l );
}void modify( int x, int y, int id ) {while( top[x] ^ top[y] ) {if( dep[top[x]] < dep[top[y]] ) swap( x, y );modify( 1, 1, n, dfn[top[x]], dfn[x], id );x = f[top[x]];}if( dep[x] > dep[y] ) swap( x, y );modify( 1, 1, n, dfn[x], dfn[y], id );
}node query( int num, int l, int r, int L, int R ) {if( L <= l && r <= R ) return t[num];int mid = ( l + r ) >> 1;pushdown( num );if( R <= mid ) return query( lson, l, mid, L, R );else if( mid < L ) return query( rson, mid + 1, r, L, R );else {node ans1 = query( lson, l, mid, L, R );node ans2 = query( rson, mid + 1, r, L, R );node ans;ans.l = ans1.l, ans.r = ans2.r;ans.cnt = ans1.cnt + ans2.cnt - ( ans1.r == ans2.l );return ans;}
}int query( int x, int y ) {node t;int ans = dep[x] + dep[y], tot = 0;int last_x = -1, last_y = -1;while( top[x] ^ top[y] ) {if( dep[top[x]] >= dep[top[y]] ) {t = query( 1, 1, n, dfn[top[x]], dfn[x] );tot += t.cnt;if( last_x == t.r ) tot --;last_x = t.l;x = f[top[x]];}else {t = query( 1, 1, n, dfn[top[y]], dfn[y] );tot += t.cnt;if( last_y == t.r ) tot --;last_y = t.l;y = f[top[y]];}}if( dep[x] > dep[y] ) swap( x, y ), swap( last_x, last_y );ans -= ( dep[x] << 1 );t = query( 1, 1, n, dfn[x], dfn[y] );tot += t.cnt;if( t.l == last_x ) tot --;if( t.r == last_y ) tot --;return ans - tot + 1;
}int main() {scanf( "%d", &T );while( T -- ) {scanf( "%d %d", &n, &m );cnt = 0;for( int i = 1;i <= n;i ++ )G[i].clear(), son[i] = 0;for( int i = 1, u, v;i < n;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u );}dfs1( 1, 0 );dfs2( 1, 1 );build( 1, 1, n );for( int i = 1, opt, a, b;i <= m;i ++ ) {scanf( "%d %d %d", &opt, &a, &b );if( opt & 1 ) modify( a, b, i + n );else printf( "%d\n", query( a, b ) );}}return 0;
}

路径交点

description

solution

  • 图中的每个顶点至多出现在一条路径中是对本题正解算法的条件限制/保证

  • (Pj−Qj)×(Pj+1−Qj+1)<0(P_j-Q_j)\times(P_{j+1}-Q_{j+1})<0(PjQj)×(Pj+1Qj+1)<0

    当固定第jjj层的枚举顺序时,发现这个条件限制的本质是逆序对

  • 询问有偶数个交点的路径方案数比有奇数个交点的路径方案数多多少个

    一种方案的贡献显然是(−1)cnt,cnt(-1)^{cnt},cnt(1)cnt,cnt表示这种方案下的逆序对个数

  • 相邻层给出的若干条有向边,可以构建一个邻接矩阵

  • 综上所有的信息都在暗示/匹配矩阵的行列式

    ∣P∣=∑j1,j2,...,jn(−1)τ(j1,j2...jn)a1,j1...an,jn|P|=\sum_{j_1,j_2,...,j_n}(-1)^{\tau(j_1,j_2...j_n)}a_{1,j_1}...a_{n,j_n}P=j1,j2,...,jn(1)τ(j1,j2...jn)a1,j1...an,jn

    ∑j1,j2,...,jn:j\sum_{j_1,j_2,...,j_n}:jj1,j2,...,jn:jnnn级全排列求和,τ(j1,j2,...,jn)\tau(j_1,j_2,...,j_n)τ(j1,j2,...,jn)表示排列j1,...,jnj_1,...,j_nj1,...,jn的逆序对个数

  • 知道二分图的解决方法了,接下来要扩展成kkk层图的计算

    binet-cauchy公式 ∣AB∣=∣A∣∣B∣|AB|=|A||B|AB=AB

    所以只需要算出相邻两层的矩阵,然后矩阵乘法得到最后为n1×n1n_1\times n_1n1×n1的总矩阵

    最后通过高斯消元(上三角矩阵)计算主对角线的乘积就是矩阵的行列式,也是询问的答案

code

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define mod 998244353
#define int long long
#define maxn 205
struct matrix {int n, m;int c[maxn][maxn];matrix() {n = m = 0;memset( c, 0, sizeof( c ) );}void clear() {for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ )c[i][j] = 0;}matrix operator * ( matrix &t ) const {matrix ans;ans.n = n, ans.m = t.m;for( int i = 1;i <= n;i ++ )for( int k = 1;k <= m;k ++ )if( c[i][k] )for( int j = 1;j <= t.m;j ++ )ans.c[i][j] = ( ans.c[i][j] + c[i][k] * t.c[k][j] ) % mod;return ans;}
}last, now;int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans;
}void gauss( int a[][maxn], int n ) {int ans = 1;for( int i = 1;i <= n;i ++ ) {int k = i;for( int j = i + 1;j <= n;j ++ )if( a[j][i] > a[k][i] ) k = j;if( i ^ k ) swap( a[i], a[k] ), ans *= -1;for( int j = i + 1;j <= n;j ++ ) {int t = a[j][i] * qkpow( a[i][i], mod - 2 ) % mod;for( int k = i;k <= n;k ++ )a[j][k] = ( a[j][k] - t * a[i][k] % mod + mod ) % mod;}}for( int i = 1;i <= n;i ++ )ans = ans * a[i][i] % mod;printf( "%lld\n", ( ans + mod ) % mod );
}int T, n;
int vec[maxn], edge[maxn];
signed main() {scanf( "%lld", &T );while( T -- ) {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ )scanf( "%lld", &vec[i] );for( int i = 1;i < n;i ++ )scanf( "%lld", &edge[i] );last.n = vec[1], last.m = vec[2], last.clear();for( int i = 1, u, v;i <= edge[1];i ++ ) {scanf( "%lld %lld", &u, &v );last.c[u][v] = 1;}for( int i = 2;i < n;i ++ ) {now.n = vec[i], now.m = vec[i + 1], now.clear();for( int j = 1, u, v;j <= edge[i];j ++ ) {scanf( "%lld %lld", &u, &v );now.c[u][v] = 1;}last = last * now;}gauss( last.c, vec[1] );}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317336.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

模板:CDQ分治

文章目录前言upd例题P3810 【模板】三维偏序&#xff08;陌上花开&#xff09;P2487 [SDOI2011]拦截导弹所谓CDQ分治&#xff0c;就是和由Conprour、Doctorjellyfish、QE添一同发明的分治算法 &#xff08;逃&#xff09; 前言 神奇的乱搞黑科技 CDQ分治能够通过更小的时间常…

【NET CORE微服务一条龙应用】第二章 配置中心使用

背景系列目录&#xff1a;【NET CORE微服务一条龙应用】开始篇与目录在分布式或者微服务系统里&#xff0c;通过配置文件来管理配置内容&#xff0c;是一件比较令人痛苦的事情&#xff0c;再谨慎也有湿鞋的时候&#xff0c;这就是在项目架构发展的过程中&#xff0c;配置中心存…

D - ABC Conjecture Gym - 102798D

D - ABC Conjecture Gym - 102798D 题意&#xff1a; 规定rad(n)n的所有质因子的乘积 给你一个c&#xff0c;问能否构造a和b使得abc且rad(abc)<c 题解&#xff1a; 先说结论&#xff0c;如果c可以拆分出两个一样的质因子&#xff0c;则能构造a和b 即 np1a1 * p2a2 . . .…

P7560-[JOISC 2021 Day1]フードコート【吉司机线段树】

正题 题目链接:https://www.luogu.com.cn/problem/P7560 题目大意 有nnn个队列&#xff0c;要求支持操作&#xff1a; 往[L,R][L,R][L,R]的队列中插入kkk个ccc。出队[L,R][L,R][L,R]中的kkk个元素。&#xff08;如果不足kkk个就全部出队&#xff09;求第aaa个队列中的第bbb个…

“幕后英雄”之Backing Fields【Microsoft Entity Framework Core随笔】

刘德华 有一首歌叫《马桶》&#xff0c;其中有一句歌词是&#xff1a;每一个马桶都是英雄。EFCore也有一个英雄&#xff0c;在幕后默默地任劳任怨。它就叫 "支持字段" (Backing Fields):中文版&#xff1a;https://docs.microsoft.com/zh-cn/ef/core/modeling/backin…

P4169 [Violet]天使玩偶/SJY摆棋子(CDQ分治、暴力)

解析 之前用KDtree做的一道题 由于懒不想再码一遍了 考虑CDQ分治 关键就是如何拿掉绝对值 如果只维护左下角的&#xff0c;显然就是一个经典的三维偏序问题了 但是本题不一定在左下角&#xff0c;也可能在左上、右下、右上 怎么办&#xff1f; 把坐标翻转翻转直接暴力做四遍即…

数论练习二之BSGS算法——随机数生成器,Matrix,Lunar New Year and a Recursive Sequence,Fermat‘s Last Theorem

[SDOI2013] 随机数生成器 description solution 肯定是非常想找一个通项公式来表示第nnn个数的 依据形式&#xff0c;考虑化成等比数列 xi1ka(xik)a⋅xibt⇒kba−1x_{i1}ka(x_ik)ax_ibt\Rightarrow k\frac{b}{a-1}xi1​ka(xi​k)a⋅xi​bt⇒ka−1b​ ⇒xiba−1ai−1(x1ba−…

L - Clock Master Gym - 102798L

L - Clock Master Gym - 102798L 题意&#xff1a; 给定一个数字n&#xff0c;令na1a2a3…求lcm(a1,a2,a3,…)的最大值,以loge(x)的形式输出 题解&#xff1a; lcm要求尽可能大&#xff0c;我们就要保证a1,a2,a3…尽可能为质数或质数的整数次幂&#xff0c;我们假设a1是p1x…

P7739-[NOI2021]密码箱【Splay,矩阵乘法】

正题 题目链接:https://www.luogu.com.cn/problem/P7739 题目描述 懒得概括&#xff0c;摸了。 Yelekastee 是 U 国著名的考古学家。在最近的一次考古行动中&#xff0c;他发掘出了一个远古时期的密码箱。经过周密而严谨的考证&#xff0c;Yelekastee 得知密码箱的密码和某一…

NetCore下模拟和使用Modbus工业通信协议

Tips&#xff1a;1、目前NetCore下与Modbus通信的框架主要选择了 Modbus.Net https://github.com/parallelbgls/Modbus.Net2、modbus是常用的工业通信协议&#xff0c;在软件调试时可以通过modbus pollslave模拟通信通过达到调试目的&#xff0c;下图是我使用软件1&#xff09…

codeforces:65

文章目录前言CF65A Harry Potter and Three SpellsDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\text{Code}CodeCF65B Harry Potter and the History of MagicDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\…

C - Rencontre Gym - 102798C

C - Rencontre Gym - 102798C 参考题解&#xff1a; 参考一 参考二 题意&#xff1a; 有一棵树&#xff0c;树上的点分为三种&#xff0c;&#xff08;一个点可以为多种&#xff09;&#xff0c;现在分别在三种点中随机选一点a&#xff0c;b&#xff0c;c&#xff0c;然后找到…

API标准化成为技术团队面临的最大挑战

调查表明&#xff0c;API 标准化成为了技术团队面临的最大挑战。SmartBear 发布了 2019 年 API 状态报告“The State of API 2019”&#xff0c;此报告旨在为 API 行业建立关于软件团队在 2019 年规划、设计、开发、测试、记录和监控 API 的方法、实践和工具的基准。此次调查有…

线性代数五之高斯消元——[SDOI2010]外星千足虫,[HNOI2013]游走,[HNOI2011]XOR和路径,[hdu 4035]Maze

多类型高斯消元杂题[SDOI2010]外星千足虫descriptionsolutioncode[HNOI2013]游走descriptionsolutioncode[HNOI2011]XOR和路径descriptionsolutioncodeMaze(树上高斯消元)problemsolutioncode[SDOI2010]外星千足虫 description solution 高斯消元的模板题 虽然感觉问了个最…

P6117-[JOI 2019 Final]コイン集め【贪心】

正题 题目链接:https://www.luogu.com.cn/problem/P6117 题目大意 平面上有2n2n2n的硬币&#xff0c;要给每个硬币匹配一个x∈[1,n],y∈[1,2]x\in[1,n],y\in[1,2]x∈[1,n],y∈[1,2]的位置&#xff08;不能重复&#xff09;。 使得所有硬币和它们匹配位置的曼哈顿距离之和最小…

CF788789(div1div2)

文章目录前言CF789A Anastasia and pebblesDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\text{Code}CodeCF789B Masha and geometric depressionDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\text{Code}Cod…

【HDU-2376】Average distance

【HDU-2376】Average distance 题意&#xff1a; 给你一个树&#xff0c;求树上任意两个点之间的距离的平均值 题解&#xff1a; 就是求出任意两点之间的距离和然后除以边数 ”任意两点之间的距离“ 和怎么算&#xff1f; 我们去考虑边的贡献情况&#xff1a; 对于边(u,v)&…

Ocelot 资源汇总

前言最近一两年.NET Core的关注度持续上升, 微服务及云原生应用开发上采用.NET Core也越来越多&#xff0c;Ocelot 作为.NET Core平台下一款开源的API 网关开发库越来越得到社区的认可&#xff0c;应用到生产中的案例也有好几百了。春节抽空整理了现有网上公开的Ocelot相关的资…

P6698-[BalticOI 2020 Day2]病毒【AC自动机,dp,SPFA】

正题 题目链接:https://www.luogu.com.cn/problem/P6698 题目大意 有一个包含0∼G−10\sim G-10∼G−1的字符集&#xff0c;其中有nnn种变换&#xff0c;能够将一个字符ai(ai>1)a_i(a_i>1)ai​(ai​>1)变为一串字符bib_ibi​&#xff0c;当一个字符串中只剩下000和1…

[TJOI2017]城市(未解决)

[TJOI2017]城市 题意&#xff1a; 一棵树&#xff0c;现在要求你将一条边改变他的位置&#xff0c;&#xff08;即改变左右所连接的端点&#xff0c;权值不变&#xff09;&#xff0c;修改后任意两点相互可达&#xff0c;且使得两个点之间的最大交通费用最小 题解: 有O(n^2…