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 ...
随机推荐
- mysql和oracle分页
mysql分页 关键字limit,limit m,n 其中m表示起始位置的下标,下标从0开始.n表示要显示的条数,比如要查询一个表的第2到5条数据. ,; oracle分页 关键字rownum, ro ...
- iOS:捋一遍View的生命周期
一.介绍 前面介绍了VC的生命周期,闲着没事也来捋一捋View的生命周期,简单用两个类型的View来监测.一个View纯代码创建,另一个View使用Xib创建. 二 .代码 MyCodeView: ...
- 用一行Python代码制作动态二维码
在GitHub上发现了一个比较有意思的项目,只需要一行Python代码就可以快捷方便生成普通二维码.艺术二维码(黑白/彩色)和动态GIF二维码. GitHub网站参见:https://github.c ...
- Python之基本运算符
基本运算符 1.算符运算符 运算符 描述 例子 + 两个对象相加 a+b - 两个对象相减 a-b * 两个数相乘或返回一个被重复若干次的字符串 a*b / 两个数相除 a/b % 取模,返回除法的余 ...
- Oracle - 截取指定日期的alert log
工作中DBA经常会查看alert log来检查数据库后台都记录了些什么日志,如果只想看某一天或者某段时间范围的日志,能够把这些日志从大的alert log中截取下来放到一个单独的文件中,对于查看和下载 ...
- 转载:点云上实时三维目标检测的欧拉区域方案 ----Complex-YOLO
感觉是机器翻译,好多地方不通顺,凑合看看 原文名称:Complex-YOLO: An Euler-Region-Proposal for Real-time 3D Object Detection ...
- 前端之jquery2
jquery属性操作 1.html() 取出或设置html内容 // 取出html内容 var $htm = $('#div1').html(); // 设置html内容 $('#div1').htm ...
- 深入理解JVM,虚拟机类加载机制
类加载过程概览 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括以下7个阶段: 加载(Loading) 验证(Verification) 准备(Preparation) 解析(Re ...
- PHP的循环和函数
1.循环 1.1for循环 for(初始值;条件;增量){ //循环体 } 1.2while.do-while while(条件){ } ------------------------- ...
- python BeautifulSoup 爬虫运行出现 exited with code -1073741571
首先,exited with code -1073741571意思是栈溢出.具体可以看https://blog.csdn.net/vblittleboy/article/details/6613815 ...