[luogu P4230] 连环病原体

题意

给定一个长度为 \(n\) 的边序列, 当这个序列的一个子区间内的边都加入图中时产生了环则称其为"加强区间", 求序列中的每条边在多少个加强区间中.

\(n\le 4\times 10^5,|V|\le 2\times 10^5\).

题解

想打休闲板子于是想起了这道上古XCR题...XCR #12好像要咕?

首先有一个显然的沙雕性质: 如果一个子区间是加强区间, 那么所有包含这个子区间的区间也是加强区间.

接着我们按照套路, 求所有以 \(i\) 为右端点的加强区间对答案产生的贡献. 这部分需要快速求.

根据上面的沙雕性质, 我们只要求出以 \(i\) 为右端点的最短加强区间的左端点 \(l\), 那么所有小于 \(l\) 的左端点也是加强区间. 于是对于所有坐标为 \(k\) 且 \(k<l\) 的位置都会产生 \(k\) 的贡献, 而对 \(k\in [l,i]\) 则会产生 \(l\) 的贡献. 于是就变成了区间加等差数列单点求值, 随手拉个线段树就可以搞了.

问题变成怎么求最短加强区间. 不难发现因为有上面的沙雕单调性直接双指针就可以了. 但是加边/删边是随机的, 所以只能用LCT维护.

跑得巨快无比. 虽然数据范围有 \(2\times 10^5\) 个点但是我的常数大如狗的LCT板子极限数据才跑了 \(300\texttt{ms}\)...

记得当时毒瘤oscar造数据的时候专门卡了查完根不Splay的选手233333

参考代码

#include <bits/stdc++.h>

const int MAXN=4e5+10;
typedef long long intEx; struct LCT{
#define lch chd[0]
#define rch chd[1]
#define kch chd[k]
#define xch chd[k^1]
struct Node{
bool rev;
Node* prt;
Node* pprt;
Node* chd[2];
Node():rev(false),prt(NULL),pprt(NULL),chd{NULL,NULL}{}
void Flip(){
if(this!=NULL){
this->rev=!this->rev;
std::swap(this->lch,this->rch);
}
}
void PushDown(){
if(this!=NULL&&this->rev){
this->lch->Flip();
this->rch->Flip();
this->rev=false;
}
}
};
std::vector<Node*> N;
LCT(int n):N(n+1){
for(int i=1;i<=n;i++)
N[i]=new Node();
}
void Rotate(Node* root,int k){
Node* tmp=root->xch;
root->PushDown();
tmp->PushDown();
tmp->prt=root->prt;
if(root->prt==NULL){
tmp->pprt=root->pprt;
root->pprt=NULL;
}
else if(root->prt->lch==root)
root->prt->lch=tmp;
else
root->prt->rch=tmp;
root->xch=tmp->kch;
if(root->xch!=NULL)
root->xch->prt=root;
tmp->kch=root;
root->prt=tmp;
}
void Splay(Node* root){
while(root->prt!=NULL){
int k=root->prt->lch==root;
if(root->prt->prt==NULL)
Rotate(root->prt,k);
else{
int d=root->prt->prt->lch==root->prt;
Rotate(k==d?root->prt->prt:root->prt,k);
Rotate(root->prt,d);
}
}
}
void Expose(Node* root){
Splay(root);
root->PushDown();
if(root->rch){
root->rch->pprt=root;
root->rch->prt=NULL;
root->rch=NULL;
}
}
bool Splice(Node* root){
Splay(root);
if(root->pprt==NULL)
return false;
Expose(root->pprt);
root->pprt->rch=root;
root->prt=root->pprt;
root->pprt=NULL;
return true;
}
void Access(Node* root){
Expose(root);
while(Splice(root));
}
void Evert(Node* root){
Access(root);
root->Flip();
}
void Link(int a,int b){
Node* x=N[a];
Node* y=N[b];
Evert(y);
y->pprt=x;
}
void Cut(int a,int b){
Node* x=N[a];
Node* y=N[b];
Evert(x);
Access(y);
y->PushDown();
y->lch->prt=NULL;
y->lch=NULL;
}
Node* FindRoot(int x){
Node* cur=N[x];
Access(cur);
while(cur->lch)
cur=cur->lch;
Splay(cur);
return cur;
}
#undef lch
#undef rch
#undef xch
#undef kch
}; struct Node{
int l;
int r;
intEx add;
intEx delta;
Node* lch;
Node* rch;
Node(int,int);
void PushDown();
intEx Query(int);
void Add(intEx,intEx);
void Add(int,int,intEx,intEx);
}; int n;
int v;
std::pair<int,int> E[MAXN]; int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&E[i].first,&E[i].second);
v=std::max(E[i].first,v);
v=std::max(E[i].second,v);
}
Node* N=new Node(1,n);
LCT* T=new LCT(v);
int l=0;
for(int i=1;i<=n;i++){
while(T->FindRoot(E[i].first)==T->FindRoot(E[i].second)){
++l;
T->Cut(E[l].first,E[l].second);
}
T->Link(E[i].first,E[i].second);
if(l!=0){
N->Add(l+1,i,l,0);
N->Add(1,l,1,1);
}
}
for(int i=1;i<=n;i++)
printf("%lld%c",N->Query(i)," \n"[i==n]);
return 0;
} inline void Node::PushDown(){
if(this->add!=0||this->delta!=0){
this->lch->Add(this->add,this->delta);
this->rch->Add(this->add+this->delta*(this->rch->l-this->l),this->delta);
this->add=this->delta=0;
}
} inline void Node::Add(intEx a,intEx d){
if(this!=NULL){
this->add+=a;
this->delta+=d;
}
} intEx Node::Query(int x){
if(this->l==this->r)
return this->add;
else{
this->PushDown();
if(x<=this->lch->r)
return this->lch->Query(x);
else
return this->rch->Query(x);
}
} void Node::Add(int l,int r,intEx a,intEx d){
if(l<=this->l&&this->r<=r)
this->Add(a+(this->l-l)*d,d);
else{
this->PushDown();
if(l<=this->lch->r)
this->lch->Add(l,r,a,d);
if(this->rch->l<=r)
this->rch->Add(l,r,a,d);
}
} Node::Node(int l,int r):l(l),r(r),add(0),delta(0),lch(NULL),rch(NULL){
if(l!=r){
int mid=(l+r)>>1;
this->lch=new Node(l,mid);
this->rch=new Node(mid+1,r);
}
}

[luogu P4230]连环病原体的更多相关文章

  1. LCT总结

    LCT总结 类比树剖,树剖是通过静态地把一棵树剖成若干条链然后用一种支持区间操作的数据结构维护(比如线段树.树状数组),而LCT是动态地去处理这个问题. 大家都知道树剖用线段树维护,而LCT用\(sp ...

  2. LCT[Link-Cut-Tree学习笔记]

    部分摘抄于 FlashHu candy99 所以文章篇幅较长 请有足够的耐心(不是 其实不用学好splay再学LCT的-/kk (至少现在我平衡树靠fhq) 如果学splay的话- 也许我菜吧-LCT ...

  3. luogu P1526 [NOI2003]智破连环阵 搜索+最大匹配+剪枝

    LINK:智破连环阵 考试的时候 题意没理解清楚 题目是指一个炸弹爆炸时间结束后再放另一个炸弹 而放完一个炸弹紧接另一个炸弹.题目中存在然后二字. 这样我们可以发现某个炸弹只会炸连续的一段. 但是 由 ...

  4. Luogu 魔法学院杯-第二弹(萌新的第一法blog)

    虽然有点久远  还是放一下吧. 传送门:https://www.luogu.org/contest/show?tid=754 第一题  沉迷游戏,伤感情 #include <queue> ...

  5. luogu p1268 树的重量——构造,真正考验编程能力

    题目链接:http://www.luogu.org/problem/show?pid=1268#sub -------- 这道题费了我不少心思= =其实思路和标称毫无差别,但是由于不习惯ACM风格的题 ...

  6. [luogu P2170] 选学霸(并查集+dp)

    题目传送门:https://www.luogu.org/problem/show?pid=2170 题目描述 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一 ...

  7. [luogu P2647] 最大收益(贪心+dp)

    题目传送门:https://www.luogu.org/problem/show?pid=2647 题目描述 现在你面前有n个物品,编号分别为1,2,3,--,n.你可以在这当中任意选择任意多个物品. ...

  8. Luogu 考前模拟Round. 1

    A.情书 题目:http://www.luogu.org/problem/show?pid=2264 赛中:sb题,直接暴力匹配就行了,注意一下读入和最后一句话的分句 赛后:卧槽 怎么只有40 B.小 ...

  9. luogu P2580 于是他错误的点名开始了

    luogu  P2580 于是他错误的点名开始了 https://www.luogu.org/problem/show?pid=2580 题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人. 他会一边 ...

随机推荐

  1. vue路由管理-保留滚动位置功能、按需加载模块名自定义

    路由管理:保留滚动位置 其实现与组件的keep-alive相关,仅设置了keep-aive的页面,实施保留回退位置能力. keep-alive介绍 作用 把切换出去的组件保留在内存中,可以保留它的状态 ...

  2. POJ 1740(构造博弈)

    题目链接: https://cn.vjudge.net/problem/POJ-1740 题目描述: Alice and Bob decide to play a new stone game.At ...

  3. 基于asp.net mvc的近乎产品开发培训课程(第四讲)

    演示产品源码下载地址:http://www.jinhusns.com/Products/Download  演示产品源码下载地址:http://www.jinhusns.com/Products/Do ...

  4. new~mac os 给终端命令写alias(及其他常用命令)及软连接

    配置执行顺序 优先级 配置 说明 1 /etc/profile 系统级别 —— 不推荐修改 2 /etc/paths 系统级别 —— 不推荐修改 3 ~/.profile 用户设置 4 ~/.bash ...

  5. Oracle简介及安装

    一.轨迹 二.Oracle简介 Oracle是现在全世界最大的数据库提供商,编程语言提供商,应用软件提供商,它的地位等价于微软的地位. Oracle在古希腊神话中被称为“神谕”,指的是上帝的宠儿,在中 ...

  6. eclipse设置成保护眼的背景色

    长时间的使用eclipse开发会很累吧  设置一个保护眼睛的豆沙绿色 不刺眼 是不是会更好一些呢 那么如何设置呢现在就教大家   工具/原料 eclipse jdk 方法/步骤 首先打开eclipse ...

  7. github小白上传本地代码及更新代码到GitHub及华为云教程

    上传本地代码 第一步:去github上创建自己的Repository,创建页面如下图所示: 红框为新建的仓库的https地址 第二步: echo "# Test" >> ...

  8. 100行代码实现现代版Router

      原文:http://www.html-js.com/article/JavaScript-version-100-lines-of-code-to-achieve-a-modern-version ...

  9. python并发编程-线程和锁

    什么是线程 进程:资源分配单位 线程:cpu执行单位(实体),每一个py文件中就是一个进程,一个进程中至少有一个线程 线程的两种创建方式: from multiprocessing import Pr ...

  10. git 常见命令,规范 整理

    move commit to stage area(把本地的1个commit还原到 暂存区) git reset --soft HEAD~1 把其他的commit的合并到现在到分支:git cherr ...