OID天下第一 (双指针,LCT,线段树)
题面
或曰:“笑长天下第一!”,OID 喜得合不拢嘴:“哈哈哈哈哈哈……”
OneInDark 是天下第一的。
OneInDark 给了你一个
n
n
n 个点
m
m
m 条边的无向图(无重边自环),点标号为
1
∼
n
1 ∼ n
1∼n。祂想要考考你,有多少对整数对
(
l
,
r
)
(l, r)
(l,r) 满足:
- 1
≤
l
≤
r
≤
n
1 ≤ l ≤ r ≤ n
1≤l≤r≤n
- 如果把区间
[
l
,
r
]
[l, r]
[l,r] 内的点以及它们之间的边保留下来,其他的点和边都扔掉,那么留下来的这张图恰好是一条链。
注:链必须是连通的图。特别地,一个点的图也是链。
n
,
m
≤
2.5
×
1
0
5
n,m\leq 2.5\times10^5
n,m≤2.5×105
题解
既然它是一条链,就没有度数大于 2 的点,同时又无环。
如果无环,那么就是森林(重点:一棵树也是森林),森林成为连通图只需要满足一个条件:点数-边数=1。同时由于森林满足 点数-边数 ≥ 1,所以该条件等价于(点数-边数)取得最小值 1 。
于是,我们认定链要(先后)满足三个条件:
- 每个点的度数不超过 2(读书超过 2 的点个数为 0)。
- 无环。
- (点数 - 边数) 取得最小值 1 。
如果固定区间右端点
R
R
R,我们会发现只满足前两个条件的区间左端点
L
L
L 是连续的,从某个位置一直到
R
R
R。同时若区间
[
L
,
R
]
[L,R]
[L,R] 满足前两个条件,那么区间
[
L
,
R
−
1
]
[L,R-1]
[L,R−1] (如果非空的话)也一定满足前两个条件。所以我们用双指针(曰Two Pointers,曰尺取(?)……)配合LCT(判断环),求出对于每个右端点的最远合法——仅对前两个条件合法——的左端点。
这时候要满足第三个条件,就很简单了。我们用线段树,维护左端点在每个位置时的(点数-边数)最小值及其个数。
时间复杂度
O
(
(
n
+
m
)
log
n
)
O((n+m)\log n)
O((n+m)logn) 。
CODE
做 LCT 要谨记一点:平衡树上凡是访问过的链,都得Splay旋到根,相当于对Splay进行一次“训练”,不然复杂度不对。
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<ctime>
#include<queue>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 250005
#define LL long long
#define ULL unsigned long long
#define UI unsigned int
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define eps (1e-4)
#define BI bitset<1002>
#pragma GCC optimize(2)
LL read() {
LL f=1,x=0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f*x;
}
void putpos(LL x) {
if(!x) return ;
putpos(x/10); putchar('0'+(x%10));
}
void putnum(LL x) {
if(!x) putchar('0');
else if(x < 0) putchar('-'),putpos(-x);
else putpos(x);
}
void AIput(LL x,char c) {putnum(x);putchar(c);}
int n,m,s,o,k;
// -------------------------------------START >>>
struct tr{
int s[2],fa,lz;
tr(){s[0]=s[1]=fa=lz=0;}
}tre[MAXN];
int isroot(int x) {return tre[tre[x].fa].s[0] != x && tre[tre[x].fa].s[1] != x;}
int whichson(int x) {return tre[tre[x].fa].s[1] == x;}
int update(int x) {
if(!x) return x;
tre[tre[x].s[0]].fa = tre[tre[x].s[1]].fa = x;
tre[0].fa = 0;
return x;
}
void pushdown(int x) {
if(tre[x].lz) {
swap(tre[x].s[0],tre[x].s[1]);
tre[tre[x].s[0]].lz ^= 1;
tre[tre[x].s[1]].lz ^= 1;
tre[x].lz = 0;
}return ;
}
void rotat(int x) {
int y = tre[x].fa,z = tre[y].fa;
int d = whichson(x),d2 = whichson(y),d3 = isroot(y);
tre[y].s[d] = tre[x].s[d^1];
tre[x].s[d^1] = y; tre[x].fa = z;
tre[tre[y].s[d]].fa = y; tre[y].fa = x;
if(!d3) tre[z].s[d2] = x; tre[0].fa = 0;
return ;
}
void pushup(int x) {
static int st[MAXN],tp;
st[tp = 1] = x;
while(!isroot(x)) st[++ tp] = tre[x].fa,x = tre[x].fa;
while(tp > 0) pushdown(st[tp --]);
return ;
}
int splay(int x) {
pushup(x);
while(!isroot(x)) {
int y = tre[x].fa;
if(!isroot(y) && whichson(x) == whichson(y)) rotat(y);
rotat(x);
}return x;
}
// ---------------------------SPLAY
int Access(int x) {
int p = 0,xx = x;
while(x) {
splay(x);
tre[x].s[1] = p;
p = update(x);
x = tre[x].fa;
}return splay(xx);
}
void Makeroot(int x) {Access(x);tre[x].lz ^= 1;}
int Findroot(int x) {Access(x);while(tre[x].s[0])x=tre[x].s[0];return splay(x);}
void Cut(int x,int y) {Makeroot(x);Access(y);tre[y].s[0]=tre[x].fa=0;update(y);}
void Link(int x,int y) {Makeroot(x);tre[x].fa = y;return ;}
// ---------------------------LCT
int hd[MAXN],v[MAXN<<1],nx[MAXN<<1],cne;
int ind[MAXN],cnd;
map<int,bool> mp[MAXN];
void ins(int x,int y) {
nx[++ cne] = hd[x]; v[cne] = y; hd[x] = cne;
}
void del(int x) {
for(int i = hd[x];i;i = nx[i]) {
if(mp[min(x,v[i])][max(x,v[i])]) {
Cut(x,v[i]);
mp[min(x,v[i])][max(x,v[i])] = 0;
ind[x] --; ind[v[i]] --;
if(ind[x] == 2) cnd --;
if(ind[v[i]] == 2) cnd --;
}
}return ;
}
int pl[MAXN];
struct it{
int nm,ct;
it(){nm=0x3f3f3f3f;ct=0;}
}tr[MAXN<<2];
int lz[MAXN<<2],M;
it merg(it a,it b) {
if(a.nm > b.nm) swap(a,b);
if(a.nm == b.nm) a.ct += b.ct;
return a;
}
it operator + (it a,int b) {a.nm += b; return a;}
void maketree(int n) {
M=1;while(M<n+2)M<<=1;
for(int i = 1;i <= n;i ++) {
tr[M+i].nm = 0;tr[M+i].ct = 1;
}
for(int i = M-1;i > 0;i --) {
tr[i] = merg(tr[i<<1],tr[i<<1|1]);
}return ;
}
void addtree(int l,int r,int y) {
int s = M+l-1,t = M+r+1;
while(s || t) {
if(s<M) tr[s] = merg(tr[s<<1],tr[s<<1|1]) + lz[s];
if(t<M) tr[t] = merg(tr[t<<1],tr[t<<1|1]) + lz[t];
if((s>>1) ^ (t>>1)) {
if(!(s&1)) tr[s^1]=tr[s^1]+y,lz[s^1]+=y;
if(t & 1) tr[t^1]=tr[t^1]+y,lz[t^1]+=y;
}s >>= 1;t >>= 1;
}return ;
}
it findtree(int l,int r) {
it ls = it(),rs = it();
if(l > r) return ls;
int s = M+l-1,t = M+r+1;
while(s || t) {
ls = ls + lz[s];
rs = rs + lz[t];
if((s>>1) ^ (t>>1)) {
if(!(s&1)) ls = merg(ls,tr[s^1]);
if(t & 1) rs = merg(rs,tr[t^1]);
}s >>= 1;t >>= 1;
}return merg(ls,rs);
}
int main() {
freopen("txdy.in","r",stdin);
freopen("txdy.out","w",stdout);
n = read();m = read();
for(int i = 1;i <= m;i ++) {
s = read();o = read();
ins(s,o); ins(o,s);
}
int st = 1;
maketree(n);
LL ans = 0;
for(int i = 1;i <= n;i ++) {
addtree(1,i,1);
for(int j = hd[i];j;j = nx[j]) {
s = i; o = v[j];
while(o >= st && o <= i && Findroot(o) == Findroot(s)) {
del(st ++);
}
if(o >= st && o <= i) {
Link(s,o);
mp[min(s,o)][max(s,o)] = 1;
ind[s] ++; ind[o] ++;
if(ind[s] == 3) cnd ++;
if(ind[o] == 3) cnd ++;
}
if(v[j] < i) {
addtree(1,v[j],-1);
}
}
while(cnd > 0) del(st ++);
pl[i] = st;
it as = findtree(pl[i],i);
if(as.nm == 1) ans += as.ct;
}
AIput(ans,'\n');
return 0;
}
OID天下第一 (双指针,LCT,线段树)的更多相关文章
- [Sdoi2017]树点涂色 [lct 线段树]
[Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...
- BZOJ4817[Sdoi2017]树点涂色——LCT+线段树
题目描述 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进 ...
- 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]
树点涂色 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1 ...
- 【bzoj4817】树点涂色 LCT+线段树+dfs序
Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...
- BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)
原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力 ...
- 【Foreign】染色 [LCT][线段树]
染色 Time Limit: 20 Sec Memory Limit: 256 MB Description Input Output Sample Input 13 0 1 0 2 1 11 1 ...
- 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树
[BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...
- [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]
题面 传送门 思路 $LCT$ 我们发现,这个1操作,好像非常像$LCT$里面的$Access$啊~ 那么我们尝试把$Access$操作魔改成本题中的涂色 我们令$LCT$中的每一个$splay$链代 ...
- BZOJ4817 [Sdoi2017]树点涂色 【LCT + 线段树】
题目 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进行这 ...
- BZOJ 3779 重组病毒 ——LCT 线段树
发现操作一很像一个LCT的access的操作. 然后答案就是路径上的虚边的数量. 然后考虑维护每一个点到根节点虚边的数量, 每次断开一条偏爱路径的时候,子树的值全部+1, 连接一条偏爱路径的时候,子树 ...
随机推荐
- python+selenium 自动化测试——显式等待详解
1.前言 之前有提到过等待函数,等待函数分为:强制等待(sleep).隐式等待(implicitly_wait),显示等待(WebDriverWait),这次以显示等待方式专门做一次总结,因为我个人是 ...
- CabloyJS v4.0.0支持工作流引擎及更多 🎉
截至2020年12月21日冬至,花了近5年时间作出最小可用NodeJS开源全栈框架,这就是CabloyJS V4.0.0 5年,90个模块,30万行代码,5400次提交(Commits),开启Node ...
- Event Loop我知道,宏任务微任务是什么鬼?
在介绍宏任务和微任务之前,先抛出一个问题.相信大家在面试的时候,会遇到这样的相似的问题: setTimeout(function(){undefined console.log('1') }); ne ...
- 基恩士的浓淡补正算法(Shading Correction Filter)的模拟实现。
知道这个算法应该有很久了,主要当时在意2个事情,一个是这个名字的翻译是在是搞笑,第二是这个算法的效果.不过一直以来都十分好奇这个算法是怎么实现的.因为之前一直无法实际的用基恩士的软件平台用不同的图片去 ...
- SAP -熟练使用T-Code SHD0
SHD0 业务顾问和开发顾问都非常熟悉的一个T-Code, 如果能合理使用它,可以省去许多增强和程序修改工作. 当我需要时,我在这里找不到任何相关文档,这就是为什么我想借此机会向我们自己的SCN提供内 ...
- Python教程——常用的os操作详情
Python自动的os库是和操作系统交互的库,常用的操作包括文件/目录操作,路径操作,环境变量操作和执行系统命令等. 文件/目录操作 获取当前目录(pwd): os.getcwd() 切换目录(cd) ...
- linux查询文件或者文件夹
查找目录:find /(查找范围) -name '查找关键字' -type d // 查找fastdfs_storage_data文件夹 find / -name fastdfs_storage_da ...
- NC14683 储物点的距离
NC14683 储物点的距离 题目 题目描述 一个数轴,每一个储物点会有一些东西,同时它们之间存在距离. 每次给个区间 \([l,r]\) ,查询把这个区间内所有储物点的东西运到另外一个储物点的代价是 ...
- esp8266模拟输入(ADC)检测问题
今天使用esp12f读取A0数据时一直出现错误; Serial.println(analogRead(A0));读取值一直为1024 因为前段时间一直用的是开发板,读取电压值正常 而从昨天换为了esp ...
- 温控器/胎压检测/电表/热泵显示控制器等,低功耗高抗干扰断/段码(字段式)LCD液晶显示驱动IC-VK2C22A/B,替代市面16C22,44*4/40*4点显示
产品品牌:永嘉微电/VINKA 产品型号:VK2C22A/B 封装形式:LQFP52/48 产品年份:新年份 概述: VK2C22是一个点阵式存储映射的LCD驱动器,可支持最大176点(44SEGx4 ...