天下第一 txdy (LCT+双指针+线段树)

天下第一 txdy

  • description
  • solution
  • code

description

djq_cpp 是天下第一的。
djq_cpp 给了你一个 n 个点 m 条边的无向图(无重边自环),点标号为 1 ∼n。祂想要考考你,
有多少对整数对 (l, r) 满足:
• 1 ≤l ≤r ≤n
• 如果把区间 [l, r] 内的点以及它们之间的边保留下来,其他的点和边都扔掉,那么留下来的这张
图恰好是一条链。
注:链必须是连通的图。特别地,一个点的图也是链。

Input
第一行两个非负整数 n, m。
接下来 m 行每行两个正整数 u, v(1 ≤u, v ≤n, u ̸= v),表示 u, v 之间有一条边。
保证图无重边自环。

Output
输出一个整数表示答案。

Sample
Input
3 3
1 2
2 3
3 1
Output
5
Explanation
(1, 1), (1, 2), (2, 2), (2, 3), (3, 3) 是符合条件的整数对。

Constraint
对于 10% 的数据,n, m ≤100。
对于 20% 的数据,n, m ≤1000。
对于 60% 的数据,n, m ≤50000。
对于另外 10% 的数据,保证每个点度数 ≤2。
对于 100% 的数据,1 ≤n ≤250000, 0 ≤m ≤250000。

solution

首先清楚为链的必要条件

  • 点数减边数=1=1=1
  • 无环
  • 每个点度数≤2\le 22

正解就是寻找辅助工具来判断点[l,r][l,r][l,r]内的所有边是否满足上面所有条件

实际上,三个条件可以分开保证后再合并

双指针法

考虑枚举点区间的右端点rrr

然后找到满足[l,r][l,r][l,r]内每个点度数都≤2\le 22的最小的lll,记为f[r]f[r]f[r]

显然随着rrr的右移,lll只会变大不会变小

  • 具体而言,利用度数did_idi,每次右端点+1+1+1后,加入新右端点连接的所有在[l,r+1][l,r+1][l,r+1]的边,并判断边连接两点是否度数超过222,如果超过就选择右移左端点,断掉原来左端点的所有已连边,直到度数不超过222才停止左端点右移

同理,双指针法

考虑枚举右端点rrr

然后找到满足[l,r][l,r][l,r]内所有边加入后无环的最小的lll,记为g[r]g[r]g[r]

显然随着rrr的右移,lll只会变大不会变小

  • 具体而言,与维护度数本质上是完全一样的,但是这里涉及到了边的动态变化,那就不得不使用动态树LCT\text{LCT}LCT了,判断新右端点的边连接的两个点原本已经连接,这条边加入就会形成环,右移左端点,断掉原来左端点的所有已连边。这些完完全全就是LCT\text{LCT}LCT的模板专场了

为了满足以上两个条件,则真正的左端点是l=max⁡(g[r],f[r])l=\max(g[r],f[r])l=max(g[r],f[r])

最后就是必须是同一条链的连通性问题

要求点数减边数=1=1=1,就可以用线段树维护点数减边数最小值,再记录最小值的个数

  • 具体而言,对于每一个右端点rrr,线段树叶子结点lll表示的意思是[l,r][l,r][l,r]区间内所有边都加入后,点数减边数的最小值。写法上,是将线段树与无环的判断放在一起写的

考场上硬刚LCT的人真的是强者

code

#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 250005
int n, m, top, sta[maxn], pos[maxn], deg[maxn];
vector < int > G[maxn];namespace LCT {struct node { int son[2], fa, tag; }t[maxn];bool root( int x ) { return t[t[x].fa].son[0] ^ x and t[t[x].fa].son[1] ^ x; }void reverse( int x ) { swap( t[x].son[0], t[x].son[1] ); t[x].tag ^= 1; }void pushdown( int x ) {if( ! t[x].tag ) return;if( t[x].son[0] ) reverse( t[x].son[0] );if( t[x].son[1] ) reverse( t[x].son[1] );t[x].tag ^= 1;}void rotate( int x ) {int fa = t[x].fa;int Gfa = t[fa].fa;int d = t[fa].son[1] == x;if( ! root( fa ) ) t[Gfa].son[t[Gfa].son[1] == fa] = x;t[x].fa = Gfa;if( t[x].son[d ^ 1] ) t[t[x].son[d ^ 1]].fa = fa;t[fa].son[d] = t[x].son[d ^ 1];t[x].son[d ^ 1] = fa;t[fa].fa = x;}void splay( int x ) {sta[++ top] = x; int y = x;while( ! root( y ) ) sta[++ top] = y = t[y].fa;while( top ) pushdown( sta[top --] );while( ! root( x ) ) {int fa = t[x].fa, Gfa = t[fa].fa;if( ! root( fa ) ) (t[Gfa].son[0] == fa) ^ (t[fa].son[0] == x) ? rotate( x ) : rotate( fa );rotate( x ); }}void access( int x ) { for( int son = 0;x;son = x, x = t[x].fa ) splay( x ), t[x].son[1] = son; }void makeroot( int x ) { access( x ); splay( x ); reverse( x ); }void split( int x, int y ) { makeroot( x ); access( y ); splay( y ); }void link( int x, int y ) { makeroot( x ); t[x].fa = y; }void cut( int x, int y ) { split( x, y ); t[x].fa = t[y].son[0] = 0; }int findroot( int x ) { access( x ); splay( x ); while( t[x].son[0] ) pushdown( x ), x = t[x].son[0]; splay( x ); return x; }bool check( int x, int y ) { makeroot( x ); return findroot( y ) == x; }
}struct node { int ans, cnt, tag; }t[maxn << 2];
namespace SGT {#define lson now << 1#define rson now << 1 | 1#define mid  (l + r >> 1)node operator + ( node x, node y ) {if( x.ans < y.ans ) return x;else if( x.ans > y.ans ) return y;else { x.cnt += y.cnt; return x; }}void pushdown( int now ) {if( ! t[now].tag ) return;t[lson].ans += t[now].tag;t[lson].tag += t[now].tag;t[rson].ans += t[now].tag;t[rson].tag += t[now].tag;t[now].tag = 0;}void build( int now, int l, int r ) {t[now] = { 0, 1, 0 };if( l == r ) return;build( lson, l, mid );build( rson, mid + 1, r );t[now] = t[lson] + t[rson];}void modify( int now, int l, int r, int L, int R, int v ) {if( R < l or r < L ) return;if( L <= l and r <= R ) { t[now].ans += v; t[now].tag += v; return; }pushdown( now );modify( lson, l, mid, L, R, v );modify( rson, mid + 1, r, L, R, v );t[now] = t[lson] + t[rson]; t[now].tag = 0; //因为重载的写法问题 t[now]=t[lson]/t[rson] 会把儿子的懒标记也赋过来 但实际上now这里是不该存在懒标记的}node query( int now, int l, int r, int L, int R ) { if( r < L or R < l ) return { inf, 0, 0 };if( L <= l and r <= R ) return t[now];pushdown( now );return query( lson, l, mid, L, R ) + query( rson, mid + 1, r, L, R );}
}int main() {scanf( "%d %d", &n, &m );for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u );}for( int r = 1, l = 1;r <= n;r ++ ) {//枚举位置r作为右端点 //双指针l求出最远的满足度数<=2的条件sort( G[r].begin(), G[r].end() );for( int i : G[r] ) { //把每条r相连的属于[l,r]的边加进来 if( i > r ) break;while( l <= i and ( deg[i] == 2 or deg[r] == 2 ) ) {//在加这条边之前 两点度数就已经等于2 加了过后肯定不满足度数<=2的条件//这个时候说明l左端点应当右移//知道两点度数都<2为止 for( int j : G[l] )if( l < j and ( j < r or ( j == r and l < i ) ) )deg[l] --, deg[j] --;l ++;}if( l <= i ) deg[i] ++, deg[r] ++;//这条边还在调整后新区间内[l',r]内才真的加入}pos[r] = l;}SGT :: build( 1, 1, n );long long ans = 0;for( int r = 1, l = 1;r <= n;r ++ ) {SGT :: modify( 1, 1, n, 1, r, 1 );for( int i : G[r] ) {if( i > r ) break;while( l <= i and LCT :: check( i, r ) ) {for( int j : G[l] )if( l < j and ( j < r or ( j == r and l < i ) ) )LCT :: cut( l, j );/*不能写成if(l<j and j<= r) 上面同理因为新加一条边是i-r有可能i就恰好是l发现i和r已经联通就必须去除掉l连接的边l里面就会访问到l-r这条边 但是这里还没有加错误写法就会删去一条根本没加过的边导致错误 */l ++;}if( l <= i ) LCT :: link( i, r );SGT :: modify( 1, 1, n, 1, i, -1 );}pos[r] = max( pos[r], l );node now = SGT :: query( 1, 1, n, pos[r], r );if( now.ans == 1 ) ans += now.cnt;}printf( "%lld\n", ans );return 0;
}

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

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

相关文章

Acwing 1083. Windy数

Acwing 1083. Windy数 题意&#xff1a; Windy 定义了一种 Windy 数&#xff1a;不含前导零且相邻两个数字之差至少为 2 的正整数被称为 Windy 数。 Windy 想知道&#xff0c;在 A 和 B 之间&#xff0c;包括 A 和 B&#xff0c;总共有多少个 Windy 数&#xff1f; 题解&am…

【招聘(南京)】南京纳龙科技有限公司招高级.net开发工程师

南京纳龙科技有限公司成立于2002年12月&#xff0c;隶属纳龙科技在南京成立的研发中心&#xff0c;坐落于南京市雨花台区。公司立志以守护人类心脏健康为使命&#xff0c;专注推动心电信息化技术的发展&#xff0c;为全国各级医疗机构提供心电检查、诊断一体化的解决方案。公司…

模板:k短路(可并堆)

所谓k短路&#xff0c;就是第k短的路。 &#xff08;逃&#xff09; 解析 给出一个有向图&#xff0c;求 s−ts-ts−t 的不严格第 k 短的路径。 A*算法 对于一个状态 (x,cost)(x,cost)(x,cost)&#xff0c;即到 xxx 时走过长度为 costcostcost&#xff0c;定义一个估价函数&a…

大鱼吃小鱼(fhq-treap/线段树二分+贪心)

大鱼吃小鱼descriptionsolutioncodedescription 《大鱼吃小鱼》是一款经典的儿童益智类游戏&#xff0c;在游戏中&#xff0c;玩家所操控的“大鱼”只能吃掉体积严格小于自己的“小鱼”&#xff0c;然后玩家所操控的“大鱼”的体积就会增加“小鱼”的体积这么多的量。 知名主…

Acwing 1081. 度的数量(以及本人对数位dp的浅薄理解)

题意&#xff1a; 求给定区间 [X,Y] 中满足下列条件的整数个数&#xff1a;这个数恰好等于 K 个互不相等的 B 的整数次幂之和。 题解&#xff1a; 数位DP 技巧1&#xff1a;[X,Y]>f(Y)-f(X-1) 技巧2&#xff1a;用树的方式来考虑。 在本题中&#xff0c;题意是问[X,Y]中…

EFCore动态切换Schema

最近做个分库分表项目&#xff0c;用到schema的切换感觉还是有些坑的&#xff0c;在此分享下。 先简要说下我们的分库分表分库分表规则我定的规则是&#xff0c;订单号&#xff08;数字&#xff09;除以16&#xff0c;得出的结果为这个订单所在的数据库&#xff0c;然后他的余数…

YBTOJ:工作评估(分块)

解析 首先想想 O(nm)O(nm)O(nm) 怎么做。 从左往右扫&#xff0c;不断把当前值和 x0x_0x0​ 取 max⁡\maxmax 即可。 考虑正解&#xff1a; 设 f(l,r,w)f(l,r,w)f(l,r,w) 为初始为 www&#xff0c;工作区间为 (l,r)(l,r)(l,r) 结束后的价值&#xff0c;s(l,r)∑ilrais(l,r)\s…

黑客(续) (压位高精+状压dp)

黑客&#xff08;续&#xff09;descriptionsolutioncodedescription 【问题描述】 在破解了世界首富 Bychaha 的银行账户后&#xff0c;知名黑客 pks 发现&#xff0c;要得到 Bychaha 的全部财产&#xff0c;必须再破解一道密码。 作为客户账户安全的最后一道防线&#xff0…

东莞.NET俱乐部线下技术沙龙-活动报名

自广州.NET技术俱乐部在2018年12月08日线下活动顺利开展后&#xff0c;东莞作为兄弟城市&#xff0c;也想通过线下活动的方式&#xff0c;点燃东莞.NET技术的熊熊之火。现决定先借助广州、深圳兄弟城市的帮助下&#xff0c;开展一场东莞方主办的线下活动&#xff0c;聚集东莞本…

Acwing 1084. 数字游戏 II

Acwing 1084. 数字游戏 II 题意&#xff1a; 指定一个整数闭区间 [a.b]&#xff0c;问这个区间内有多少个取模数。 取模数&#xff1a;这种数字必须满足各位数字之和 mod N 为 0。 题解&#xff1a; 数位dp 这里不细讲数位dp了&#xff0c;可以看看 Acwing 1081. 度的数量&…

ybtoj洛谷P3268:圆的异或并(扫描线)

解析 很神奇的一道题。 关键条件&#xff1a;任意两个圆无交。 把一个圆分成上下两个圆弧&#xff0c;那么所有圆弧的高度关系不会发生变化。 所以可以开一个 set&#xff0c;维护一个从左往右扫的扫描线&#xff0c;按照当前扫描线的横坐标定义比较符号&#xff0c;在圆的最…

如何撰写较受欢迎的技术文章

本来我这篇文章的标题是 “如何撰写受欢迎的技术文章”&#xff0c;但反复斟酌之下&#xff0c;还是加了一个“较”字&#xff0c;这主要是考虑我不是什么知名作者&#xff0c;写的文章大多也谈不上很受欢迎&#xff0c;贸然地谈“受欢迎” 是有点忐忑的&#xff0c;而改成现在…

朝鲜时蔬(分数据点写算法+毒瘤数学)

朝鲜时蔬decriptionsolutioncodedecription 对于一个有穷非空正整数集合S{x1,x2,x3,...,xn}⊂N(n≥1)S\{x_1,x_2,x_3,...,x_n\}\subset N^(n\ge 1)S{x1​,x2​,x3​,...,xn​}⊂N(n≥1)&#xff0c;定义其和sum(S)sum(S)sum(S)为所有元素的和 sum(S)x1...xnsum(S)x_1...x_nsum…

洛谷P7515:矩阵游戏(差分约束)

解析 如果没有元素均要在 [0,1e6][0,1e6][0,1e6] 的条件&#xff0c;可以很容易的构造出一个合法解。 那么我们就要通过调整得到的解&#xff0c;使所有数都在合法范围内。 注意到&#xff0c;每次给某一行/列依次1,-1,1,-1…这样仍然符合要求。 让每一行/列错开&#xff0c;…

Recursive sequence HDU - 5950

Recursive sequence HDU - 5950 题意&#xff1a; 给你一个式子&#xff1a;f[n]2f[n-2]f[n-1]n4 给你f[1]和f[2]&#xff0c;给你一个n&#xff0c;求f[n] f[1],f[2],n<231 题解&#xff1a; 很明显&#xff0c;矩阵快速幂&#xff0c;但是太久没做这种题&#xff0c;我…

使用Http-Repl工具测试ASP.NET Core 2.2中的Web Api项目

今天&#xff0c;Visual Studio中没有内置工具来测试WEB API。使用浏览器&#xff0c;只能测试http GET请求。您需要使用Postman&#xff0c;SoapUI&#xff0c;Fiddler或Swagger等第三方工具来执行WEB API的完整测试。在ASP.NET Core 2.2中&#xff0c;引入了一个名为“http-r…

洛谷P7518:宝石(倍增、可撤销并查集)

解析 算法一 定义 upx,kup_{x,k}upx,k​ 为节点 xxx 从自己的颜色所在位置在返祖链上往后跳 2k2^k2k 个颜色到达的节点。 可以像倍增一样的求解。 这样对于一次询问 (s,t)(s,t)(s,t) 我们就能求出 (s,lca)(s,lca)(s,lca) 这一段能取到哪里了。 对于向下的情况&#xff0c;再处…

E - Counting Cliques HDU - 5952

E - Counting Cliques HDU - 5952 题意&#xff1a; 给你n个点&#xff0c;m个边&#xff0c;还有一个s&#xff0c;问这个图中有多少个等于s的点集可以组成一个完全图 题解&#xff1a; 这题。。直接暴力搜索就行 分析复杂度的时候&#xff0c;应该考虑只有1000条边&#…

Docker最全教程之使用TeamCity来完成内部CI、CD流程(十七)

本篇教程主要讲解基于容器服务搭建TeamCity服务&#xff0c;并且完成内部项目的CI流程配置。教程中也分享了一个简单的CI、CD流程&#xff0c;仅作探讨。不过由于篇幅有限&#xff0c;完整的DevOps&#xff0c;我们后续独立探讨。 为了降低容器的使用门槛以及便于大家将容器技…

2021牛客NOIP提高组第二场T2——方格计数(组合数计数)

方格计数descriptionsolutioncodedescription 在左下角是 (&#x1d7ce;, &#x1d7ce;)&#xff0c;右上角是 (W, H)的网格上&#xff0c;有 (W 1) (H 1) 个格点。 现在要在格点上找 N个不同的点&#xff0c;使得这些点在一条直线上。并且在这条直线上&#xff0c; 相邻…