【CF938G】Shortest Path Queries(线段树分治,并查集,线性基)
【CF938G】Shortest Path Queries(线段树分治,并查集,线性基)
题面
题解
吼题啊。
对于每个边,我们用一个\(map\)维护它出现的时间,
发现询问单点,边的出现时间是区间,所以线段树分治。
既然路径最小值就是异或最小值,并且可以不是简单路径,
不难让人想到\(WC2011\)那道最大\(Xor\)路径和。
用一样的套路,我们动态维护一棵生成树,碰到一个非树边,
就把这个环的异或和丢到线性基里面去,这样子直接查就好了。
动态维护生成树直接用并查集就好了,没有必要\(LCT\)
大概就是永远不进行路径压缩,每次启发式合并。
询问的时候暴跳父亲。
然后撤销操作的话,维护一个栈,每次存下当前的修改操作,
撤销的时候倒序还原就好了。
细节很多,第一次写这样的东西,调了好久啊。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
#define MAX 200200
#define ll long long
#define pi pair<int,int>
#define mp(x,y) make_pair(x,y)
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct xxj
{
int p[31];
void insert(int x)
{
for(int i=30;~i;--i)
if(x&(1<<i))
{
if(!p[i]){p[i]=x;break;}
x^=p[i];
}
}
int Query(int x){for(int i=30;~i;--i)x=min(x,x^p[i]);return x;}
}G;
struct Node{int u,v,w;}p[MAX<<1];
pi q[MAX];
int n,m;
map<pi,int> M;
vector<Node> seg[MAX<<2];
void Modify(int now,int l,int r,int L,int R,Node e)
{
if(L>R)return;if(L<=l&&r<=R){seg[now].push_back(e);return;}
int mid=(l+r)>>1;
if(L<=mid)Modify(lson,l,mid,L,R,e);
if(R>mid)Modify(rson,mid+1,r,L,R,e);
}
int tim,cnt,L[MAX<<1],R[MAX<<1];
int f[MAX],sz[MAX],Xor[MAX];
int getf(int x){while(x!=f[x])x=f[x];return x;}
int getxor(int x){int ret=0;while(x!=f[x])ret^=Xor[x],x=f[x];return ret;}
void Divide(int now,int l,int r,xxj G)
{
vector<Node> c;c.clear();
for(int i=0,lim=seg[now].size();i<lim;++i)
{
int u=seg[now][i].u,v=seg[now][i].v,w=seg[now][i].w;
int f1=getf(u),f2=getf(v);
if(f1==f2)G.insert(getxor(u)^getxor(v)^w);
else
{
if(sz[f1]>sz[f2])swap(f1,f2),swap(u,v);
w^=getxor(v)^getxor(u);
c.push_back((Node){f1,f2,sz[f2]});
Xor[f1]=w;f[f1]=f2;sz[f2]+=sz[f1];
}
}
if(l==r)
printf("%d\n",G.Query(getxor(q[l].first)^getxor(q[l].second)));
else
{
int mid=(l+r)>>1;
Divide(lson,l,mid,G);Divide(rson,mid+1,r,G);
}
for(int i=c.size()-1;~i;--i)
{
int u=c[i].u,v=c[i].v,w=c[i].w;
sz[v]=w;f[u]=u;Xor[u]=0;
}
}
int main()
{
//freopen("938G.in","r",stdin);
//freopen("938G.out","w",stdout);
n=read();m=read();
for(int i=1;i<=m;++i)
{
int x=read(),y=read(),w=read();
p[++cnt]=(Node){x,y,w};
L[cnt]=1;M[mp(x,y)]=cnt;R[cnt]=-1;
}
int Q=read();
for(int i=1;i<=Q;++i)
{
int opt=read(),x=read(),y=read();
if(x>y)swap(x,y);
if(opt==1)
{
p[++cnt]=(Node){x,y,read()};
L[cnt]=tim+1;R[cnt]=-1;M[mp(x,y)]=cnt;
}
else if(opt==2)R[M[mp(x,y)]]=tim;
else q[++tim]=mp(x,y);
}
for(int i=1;i<=cnt;++i)if(R[i]==-1)R[i]=tim;
for(int i=1;i<=cnt;++i)Modify(1,1,tim,L[i],R[i],p[i]);
for(int i=1;i<=n;++i)f[i]=i,sz[i]=1;
Divide(1,1,tim,G);
return 0;
}
【CF938G】Shortest Path Queries(线段树分治,并查集,线性基)的更多相关文章
- $CF938G\ Shortest\ Path\ Queries$ 线段树分治+线性基
正解:线段树分治+线性基 解题报告: 传送门$QwQ$ 考虑如果只有操作3,就这题嘛$QwQ$ 欧克然后现在考虑加上了操作一操作二 于是就线段树分治鸭 首先线段树叶子节点是询问嘛这个不用说$QwQ$. ...
- 2018.09.30 bzoj4025: 二分图(线段树分治+并查集)
传送门 线段树分治好题. 这道题实际上有很多不同的做法: cdq分治. lct. - 而我学习了dzyo的线段树分治+并查集写法. 所谓线段树分治就是先把操作分成lognlognlogn个连续不相交的 ...
- bzoj4025二分图(线段树分治 并查集)
/* 思维难度几乎没有, 就是线段树分治check二分图 判断是否为二分图可以通过维护lct看看是否链接出奇环 然后发现不用lct, 并查集维护奇偶性即可 但是复杂度明明一样哈 */ #include ...
- BZOJ3237:[AHOI2013]连通图(线段树分治,并查集)
Description Input Output Sample Input 4 5 1 2 2 3 3 4 4 1 2 4 3 1 5 2 2 3 2 1 2 Sample Output Connec ...
- BZOJ3237 AHOI2013连通图(线段树分治+并查集)
把查询看做是在一条时间轴上.那么每条边都有几段存在时间.于是线段树分治就好了. 然而在bzoj上t掉了,不知道是常数大了还是写挂了. 以及brk不知道是啥做数组名过不了编译. #include< ...
- BZOJ4025 二分图(线段树分治+并查集)
之前学了一下线段树分治,这还是第一次写.思想其实挺好理解,即离线后把一个操作影响到的时间段拆成线段树上的区间,并标记永久化.之后一块处理,对于某个节点表示的时间段,影响到他的就是该节点一直到线段树根的 ...
- Bzoj1018/洛谷P4246 [SHOI2008]堵塞的交通(线段树分治+并查集)
题面 Bzoj 洛谷 题解 考虑用并查集维护图的连通性,接着用线段树分治对每个修改进行分治. 具体来说,就是用一个时间轴表示图的状态,用线段树维护,对于一条边,我们判断如果他的存在时间正好在这个区间内 ...
- BZOJ 1018: [SHOI2008]堵塞的交通traffic(线段树分治+并查集)
传送门 解题思路 可以离线,然后确定每个边的出现时间,算这个排序即可.然后就可以线段树分治了,连通性用并查集维护,因为要撤销,所以要按秩合并,时间复杂度\(O(nlog^2 n)\) 代码 #incl ...
- [BZOJ4025]二分图(线段树分治,并查集)
4025: 二分图 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2191 Solved: 800[Submit][Status][Discuss] ...
- Codeforces 1140F Extending Set of Points (线段树分治+并查集)
这题有以下几个步骤 1.离线处理出每个点的作用范围 2.根据线段树得出作用范围 3.根据分治把每个范围内的点记录和处理 #include<bits/stdc++.h> using name ...
随机推荐
- 人工智能AI芯片与Maker创意接轨(下)
继「人工智能AI芯片与Maker创意接轨」的(上)篇中,认识了人工智能.深度学习,以及深度学习技术的应用,以及(中)篇对市面上AI芯片的类型及解决方案现况做了完整剖析后,系列文到了最后一篇,将带领各位 ...
- 关于IPointerEnterHandler和IpointerExitHandler的简单说明
自己在学习UGUI背包系统时用到了,而且遇到一些问题,所以在这里写一下这两个接口的简单说明. 继承IPointerEnterHandler和IpointerExitHandler这两个接口后可以实现两 ...
- leetcode-填充同一层的兄弟节点Ⅱ
给定一个二叉树 struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *next; } 填充它的每个 ...
- python破解网吧收费系统,远控网吧电脑设备!
我今天呢 , 我就没事跟着朋友喝酒喝酒啊.喝了很多啊.晚上到旁边的酒店开了一个房间,到了酒店才十点! 感觉没啥事情干的,那就去网吧走走看把,看到是一个嘟嘟牛的,和上次是一样的.还是照常用MS170 ...
- 【坚持】Selenium+Python学习记录 DAY10
2018/05/31-2018/06/1 [官方文档](https://www.jetbrains.com/help/pycharm/set-up-a-git-repository.html) 通过p ...
- Netty源码分析第1章(Netty启动流程)---->第2节: NioServerSocketChannel的创建
Netty源码分析第一章: Server启动流程 第二节:NioServerSocketChannel的创建 我们如果熟悉Nio, 则对channel的概念则不会陌生, channel在相当于一个通 ...
- 使用spring整合Quartz实现—定时器
使用spring整合Quartz实现—定时器(Maven项目做演示) 不基于特定的基类的方法 一,开发环境以及依赖的jar包 Spring 4.2.6.RELEASE Maven 3.3.9 Jdk ...
- Vue.js 相关知识(组件)
1. 组件介绍 组件(component),vue.js最强大的功能之一 作用:封装可重用的代码,通常一个组件就是一个功能体,便于在多个地方都能调用该功能体 根组件:我们实例化的Vue对象就是一个组件 ...
- IIS 无法加载 CSS,JS的问题
IIS 能加载 aspx,但不能加载里面的 js,css ,感觉有点坑. 解决方案如下:http://www.pageadmin.net/article/20121001/479.html 原来是没有 ...
- 第十一次ScrumMeeting博客
第十一次ScrumMeeting博客 本次会议于11月29日(三)22时整在3公寓725房间召开,持续30分钟. 与会人员:刘畅.辛德泰张安澜.赵奕.方科栋. 1. 每个人的工作(有Issue的内容和 ...