[luogu P4230]连环病原体
[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]连环病原体的更多相关文章
- LCT总结
LCT总结 类比树剖,树剖是通过静态地把一棵树剖成若干条链然后用一种支持区间操作的数据结构维护(比如线段树.树状数组),而LCT是动态地去处理这个问题. 大家都知道树剖用线段树维护,而LCT用\(sp ...
- LCT[Link-Cut-Tree学习笔记]
部分摘抄于 FlashHu candy99 所以文章篇幅较长 请有足够的耐心(不是 其实不用学好splay再学LCT的-/kk (至少现在我平衡树靠fhq) 如果学splay的话- 也许我菜吧-LCT ...
- luogu P1526 [NOI2003]智破连环阵 搜索+最大匹配+剪枝
LINK:智破连环阵 考试的时候 题意没理解清楚 题目是指一个炸弹爆炸时间结束后再放另一个炸弹 而放完一个炸弹紧接另一个炸弹.题目中存在然后二字. 这样我们可以发现某个炸弹只会炸连续的一段. 但是 由 ...
- Luogu 魔法学院杯-第二弹(萌新的第一法blog)
虽然有点久远 还是放一下吧. 传送门:https://www.luogu.org/contest/show?tid=754 第一题 沉迷游戏,伤感情 #include <queue> ...
- luogu p1268 树的重量——构造,真正考验编程能力
题目链接:http://www.luogu.org/problem/show?pid=1268#sub -------- 这道题费了我不少心思= =其实思路和标称毫无差别,但是由于不习惯ACM风格的题 ...
- [luogu P2170] 选学霸(并查集+dp)
题目传送门:https://www.luogu.org/problem/show?pid=2170 题目描述 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一 ...
- [luogu P2647] 最大收益(贪心+dp)
题目传送门:https://www.luogu.org/problem/show?pid=2647 题目描述 现在你面前有n个物品,编号分别为1,2,3,--,n.你可以在这当中任意选择任意多个物品. ...
- Luogu 考前模拟Round. 1
A.情书 题目:http://www.luogu.org/problem/show?pid=2264 赛中:sb题,直接暴力匹配就行了,注意一下读入和最后一句话的分句 赛后:卧槽 怎么只有40 B.小 ...
- luogu P2580 于是他错误的点名开始了
luogu P2580 于是他错误的点名开始了 https://www.luogu.org/problem/show?pid=2580 题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人. 他会一边 ...
随机推荐
- JavaScript时间操作工具类
/** * 时间操作工具类 * * @author zwq * */ var TimeFrameUtil = { /** * 格式化日期 * @param date {Date} 日期 * @para ...
- Prometheus+Grafana打造Mysql监控平台
prometheus/node_exporter/mysqld_exporter都是由go语言编写,需要先安装GoLang环境 下载node_exporter(监控服务器的CPU.内存.存储使用情况) ...
- el-upload源码修改跳坑
之前给element-ui提了一个问题,结果没有鸟我,没办法,只能修改源码来满足需求了 (备注:element-ui2依然没有修改,为了迎合产品还是要改源码) 本文讨论的组件属性仅限于list-typ ...
- 在jQuery定义自己的扩展方法函数
今早复习昨天的练习jQuery的DropDownList联动功能,如果想看回<jQuery实现DropDownList(MVC)>http://www.cnblogs.com/insus/ ...
- ADO.NET 【实体类】【数据访问类】
认识分层结构,分层式结构是最常见,也是最重要的一种结构. 三层架构(3-tier architecture) 界面层(User Interface layer) 主要对用户的请求接受,以及数据的返回, ...
- vb.net 使用MD5密碼加密
Function MD5(ByVal strSource As String, ByVal Code As Int16) As String'使用MD5加密 Dim dataToHash As Byt ...
- C语言关于形参与实参,以及系统堆栈的关系
- ActiveMQ 控制面板信息含义
Number Of Consumers :表示消费者数量: Number Of Pending Messages :等待消费的消息,这个是当前未出队列的数量: Messages Enqueued :进 ...
- 1.Strategy Pattern(策略模式)
策略模式(Strategy Pattern): 我的理解,将代码中每个变化之处抽出,提炼成一个一个的接口或者抽象类,让这些变化实现接口或继承抽象类成为具体的变化类.再利用多态的功能,可将变化之处用接口 ...
- HDU1815(二分+2-SAT)
Building roads Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...