CF 938G Shortest Path Queries
又到了喜闻乐见的写博客清醒时间了233,今天做的依然是线段树分治
这题算是经典应用了吧,假的动态图(可离线)问题
首先不难想到对于询问的时间进行线段树分治,这样就可以把每一条边出现的时间区间扔进线段树里,考虑如何维护答案
初步的想,图上两点间异或最小值,和最大值类似。先求出一棵生成树,然后把环扔进线性基里,每次查询两点间异或值之后再扔进线性基里求最小值即可
正确性的话,因为这样环一定是有树边+非树边构成的,我们可以在任意一个点走到一个环再绕回来,中间重复走的树边因为走了两次相当于没有影响
然后我们惊喜地发现,线性基是支持撤销的,而且两点间异或值可以用带撤销并查集来做,然后线段树分治的时候回溯的时候撤销即可
然后就做完了,总复杂度\(O(n\log^2 n)\),足以通过此题
说句题外话,那个维护两点间距离的并查集我本来准备用我的可换根并查集来写了,但是发现换根操作的逆过程(即撤销)比较难写,所以最后不得已向差分低头
#include<cstdio>
#include<cctype>
#include<iostream>
#include<vector>
#include<utility>
#include<map>
#define RI register int
#define CI const int&
#define Tp template <typename T>
#define mp make_pair
using namespace std;
typedef pair <int,int> pi;
const int N=200005,R=30;
struct edge
{
int x,y,v,s,t;
}e[N<<1]; int n,m,q,opt,cnt,tim,x,y,qx[N],qy[N],top; map <pi,int> Hash;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=0)++=ch))
char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[15];
public:
inline FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
Tp inline void write(T x)
{
RI ptop=0; while (pt[++ptop]=x%10,x/=10);
while (ptop) pc(pt[ptop--]+48); pc('\n');
}
inline void flush(void)
{
fwrite(Fout,1,Ftop-Fout,stdout);
}
#undef tc
#undef pc
}F;
class Linear_Basis
{
private:
int r[100][R];
public:
inline void insert(int x,CI dep)
{
for (RI i=R-1;~i;--i) if ((x>>i)&1)
if (r[dep][i]) x^=r[dep][i]; else
{
r[dep][i]=x; for (RI j=R-1;j>i;--j)
if ((r[dep][j]>>i)&1) r[dep][j]^=x; break;
}
}
inline int query(int ret,CI dep)
{
for (RI i=R-1;~i;--i) if (r[dep][i]) ret=min(ret,ret^r[dep][i]); return ret;
}
inline void copy(CI dep)
{
for (RI i=0;i<R;++i) r[dep][i]=r[dep-1][i];
}
}LB;
class UnionFindSet
{
private:
int fa[N],size[N],val[N],stk[N];
inline int getfa(CI x)
{
return x!=fa[x]?getfa(fa[x]):x;
}
public:
inline void init(void)
{
for (RI i=1;i<=n;++i) fa[i]=i,size[i]=1;
}
inline int getval(CI x)
{
return x!=fa[x]?val[x]^getval(fa[x]):0;
}
inline int identify(CI x,CI y)
{
return getfa(x)==getfa(y);
}
inline void Union(int x,int y,CI v)
{
x=getfa(x); y=getfa(y); if (size[x]>size[y]) swap(x,y);
fa[x]=y; size[y]+=size[x]==size[y]; val[x]=v^val[x]; stk[++top]=x;
}
inline void revoke(CI tar)
{
int x; while (top>tar) x=stk[top--],size[fa[x]]-=(size[fa[x]]==size[x]+1),val[x]=0,fa[x]=x;
}
}S;
class Segment_Tree
{
private:
vector <int> pv[N<<2];
inline void expand(CI now,CI dep)
{
for (vector <int>::iterator it=pv[now].begin();it!=pv[now].end();++it)
{
int x=e[*it].x,y=e[*it].y,v=S.getval(x)^S.getval(y)^e[*it].v;
if (S.identify(x,y)) LB.insert(v,dep); else S.Union(x,y,v);
}
}
inline void calc(CI now,CI pos,CI dep,CI tp)
{
int ans=S.getval(qx[pos])^S.getval(qy[pos]);
F.write(LB.query(ans,dep)); S.revoke(tp);
}
public:
#define TN CI now=1,CI l=1,CI r=tim
#define LS now<<1,l,mid
#define RS now<<1|1,mid+1,r
inline void insert(CI beg,CI end,CI pos,TN)
{
if (beg>end) return; if (beg<=l&&r<=end) return (void)(pv[now].push_back(pos)); int mid=l+r>>1;
if (beg<=mid) insert(beg,end,pos,LS); if (end>mid) insert(beg,end,pos,RS);
}
inline void solve(TN,CI dep=1)
{
int tp=top; expand(now,dep); if (l==r) return calc(now,l,dep,tp); int mid=l+r>>1;
LB.copy(dep+1); solve(LS,dep+1); LB.copy(dep+1); solve(RS,dep+1); S.revoke(tp);
}
#undef TN
#undef LS
#undef RS
}SEG;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),F.read(m),i=1;i<=m;++i)
F.read(e[i].x),F.read(e[i].y),F.read(e[i].v),
e[i].s=1,e[i].t=-1,Hash[mp(e[i].x,e[i].y)]=i;
for (cnt=m,F.read(q),i=1;i<=q;++i)
{
F.read(opt); F.read(x); F.read(y); switch (opt)
{
case 1:
e[++cnt].x=x; e[cnt].y=y; F.read(e[cnt].v);
e[cnt].s=tim+1; e[cnt].t=-1; Hash[mp(x,y)]=cnt; break;
case 2:
e[Hash[mp(x,y)]].t=tim; Hash[mp(x,y)]=0; break;
case 3:
qx[++tim]=x; qy[tim]=y; break;
}
}
if (!tim) return 0; for (i=1;i<=cnt;++i) if (!~e[i].t) e[i].t=tim;
for (i=1;i<=cnt;++i) SEG.insert(e[i].s,e[i].t,i);
return S.init(),SEG.solve(),F.flush(),0;
}
CF 938G Shortest Path Queries的更多相关文章
- Codeforces 938G Shortest Path Queries [分治,线性基,并查集]
洛谷 Codeforces 分治的题目,或者说分治的思想,是非常灵活多变的. 所以对我这种智商低的选手特别不友好 脑子不好使怎么办?多做题吧-- 前置知识 线性基是你必须会的,不然这题不可做. 推荐再 ...
- 【CF938G】Shortest Path Queries(线段树分治,并查集,线性基)
[CF938G]Shortest Path Queries(线段树分治,并查集,线性基) 题面 CF 洛谷 题解 吼题啊. 对于每个边,我们用一个\(map\)维护它出现的时间, 发现询问单点,边的出 ...
- CF938G Shortest Path Queries 和 CF576E Painting Edges
这两道都用到了线段树分治和按秩合并可撤销并查集. Shortest Path Queries 给出一个连通带权无向图,边有边权,要求支持 q 个操作: x y d 在原图中加入一条 x 到 y 权值为 ...
- CF938G Shortest Path Queries
首先只有询问的话就是个WC的题,线性基+生成树搞一搞就行. 进一步,考虑如果修改操作只有加边怎么做. 好像也没有什么变化,只不过需要在线地往线性基里插入东西而已. 删边呢? 注意到线性基这个玩意是不支 ...
- $CF938G\ Shortest\ Path\ Queries$ 线段树分治+线性基
正解:线段树分治+线性基 解题报告: 传送门$QwQ$ 考虑如果只有操作3,就这题嘛$QwQ$ 欧克然后现在考虑加上了操作一操作二 于是就线段树分治鸭 首先线段树叶子节点是询问嘛这个不用说$QwQ$. ...
- 题解 CF938G 【Shortest Path Queries】
题目让我们维护一个连通无向图,边有边权,支持加边删边和询问从\(x\)到\(y\)的异或最短路. 考虑到有删边这样的撤销操作,那么用线段树分治来实现,用线段树来维护询问的时间轴. 将每一条边的出现时间 ...
- Shortest Path(思维,dfs)
Shortest Path Accepts: 40 Submissions: 610 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: ...
- Shortest Path
Shortest Path Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)T ...
- 74(2B)Shortest Path (hdu 5636) (Floyd)
Shortest Path Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)T ...
随机推荐
- 趣谈Linux操作系统学习笔记:第二十八讲
一.引子 磁盘→盘片→磁道→扇区(每个 512 字节) ext* 定义文件系统的格式 二.inode 与块的存储 1.块 2.不用给他分配一块连续的空间 我们可以分散成一个个小块进行存放 1.优点 2 ...
- Python与用户交互
目录 一.为什么交互? 二.如何交互? 三.Python2的交互 一.为什么交互? 让我们来回顾计算机的发明有何意义,计算机的发明是为了奴役计算机,解放劳动力.假设我们现在写了一个ATM系统取代了 ...
- C# - WinFrm应用程序调用SharpZipLib实现文件的压缩和解压缩
前言 本篇主要记录:VS2019 WinFrm桌面应用程序调用SharpZipLib,实现文件的简单压缩和解压缩功能. SharpZipLib 开源地址戳这里. 准备工作 搭建WinFrm前台界面 添 ...
- ubuntu 16.04无法连接网络;双系统无法上网;连接已断开,你现在处于断开状态
先描述一一下我的问题,若和你的一样,请继续往下看. 我是在原有Windows7系统的台式计算机中安装了ubuntu 16.04,所以目前这台计算机是双系统.打开Windows系统时有线网络正常链接.但 ...
- SQL Server内部如何管理对象的数据Page?
一个表或Index使用的数据页空间是由IAM Page Chain来管理的.SQL Server 使用一个IAM(Index Allocation Map)Page来管理数据库文件中最多4GB的空间, ...
- Redisson实现分布式锁(1)---原理
Redisson实现分布式锁(1)---原理 有关Redisson作为实现分布式锁,总的分3大模块来讲. 1.Redisson实现分布式锁原理 2.Redisson实现分布式锁的源码解析 3.Redi ...
- python基础(30):黏包、socket的其他方法
1. 黏包 1.1 黏包现象 让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd) 同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接 ...
- Python打包成exe文件很难?一分钟即可学会,并添加图标!
环境1.python 3.72.pyinstaller下载方式:2.1 python安装(略)2.2 安装pyinstaller打开DOS窗口输入以下命令:pip install pyinstalle ...
- JavaScript中break、continue和return的区别
break function myBreak() { for(var i = 0; i < 5; i++) { if(i == 3) { break; } console.log(i); } } ...
- Quest 公司的Shareplex 与 GoldenGate比较
Quest 公司的Shareplex 与 GoldenGate比较 2012-08-01 16:51:12 —————————————————————————————————————————— ...