[Codeforces 464E] The Classic Problem(可持久化线段树)

题面

给出一个带权无向图,每条边的边权是\(2^{x_i}(x_i<10^5)\),求s到t的最短路\(\mathrm{mod} \ 10^9+7\)的值

分析

显然边权存不下,由于取模会影响大小关系,不能直接取模然后跑dijkstra

考虑用可持久化线段树维护每个点到起点的距离(二进制表示),即维护一个01序列,[1,n]从低位到高位存储。

修改的时候我们要把第i位+1,如果第i位是0,直接取反就可以了。但是第i位是1的时候不仅要取反,还要进位。这里可以直接暴力把连续的一段0改成1。理论上会被卡但这题的数据比较水,不被卡的做法参考cf官方题解

另外dijkstra算法中需要比较dist值大小,从高到低比较二进制的每一位。可以维护区间hash值,查询的时候在线段树上二分。如果右区间[mid+1,r]的hash值相同,就递归比较[l,mid],否则比较[mid+1,r].

具体见代码

代码

//http://codeforces.com/problemset/problem/464/E
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#define maxn 500000
#define maxm 500000
#define maxlog 25
#define mod 1000000007
#define INF 0x3f3f3f3f
using namespace std;
int n,m,dg;//dg是二进制位数
long long pow2[maxn+5];
struct segment_tree{//主席树维护二进值位 ,下标[1,n]从低位到高位存储二进制
#define lson(x) tree[x].ls
#define rson(x) tree[x].rs
struct node{
int ls;
int rs;
long long sum;//二进制值取模mod之后的值
//既可以用来更新答案,也可以当做hash判断两端二进制是否相等
}tree[maxn*maxlog+5];
int ptr;
void push_up(int x,int l,int r){
int mid=(l+r)>>1;
tree[x].sum=tree[lson(x)].sum+tree[rson(x)].sum*pow2[mid-l+1]%mod;
tree[x].sum%=mod;
}
int insert(int &x,int last,int upos,int l,int r){
x=++ptr;
tree[x]=tree[last];
if(l==r){
tree[x].sum^=1;//+1,1变0,0变1,进位等下再处理
return tree[last].sum;
}
int mid=(l+r)>>1;
int res;
if(upos<=mid){
//upos<=mid,处理进位,[mid+1,r]对应的高位也会被进位,所以要递归下去修改
//考虑极端情况,xi都=1,那么需要进位O(m/2+m/4+m/8+...+1)≈O(m)
res=insert(tree[x].ls,tree[last].ls,upos,l,mid);
//如果res不等于0,说明之前[l,mid]就有值,要继续进位
if(res) res=insert(tree[x].rs,tree[last].rs,upos,mid+1,r);
}else{
res=insert(tree[x].rs,tree[last].rs,upos,mid+1,r);
}
push_up(x,l,r);
return res;
}
bool cmp(int x,int y,int l,int r){//比较x,y两棵主席树对应的二进制大小
if(l==r){
return tree[x].sum<tree[y].sum;
}
int mid=(l+r)>>1;
if(tree[tree[x].rs].sum==tree[tree[y].rs].sum) return cmp(tree[x].ls,tree[y].ls,l,mid);//从高位到低位,高位相同就比低位
else return cmp(tree[x].rs,tree[y].rs,mid+1,r);
}
#undef lson
#undef rson
}T; struct edge{
int from;
int to;
int next;
int len;
}E[maxm*2+5];
int head[maxn+5];
int ecnt=1;
void add_edge(int u,int v,int w){
ecnt++;
E[ecnt].from=u;
E[ecnt].to=v;
E[ecnt].len=w;
E[ecnt].next=head[u];
head[u]=ecnt;
} struct heap_node{
int id;
int rt;//对应二进制主席树的树根
heap_node(){ }
heap_node(int _id,int _rt){
id=_id;
rt=_rt;
}
friend bool operator < (heap_node p,heap_node q){
return !T.cmp(p.rt,q.rt,0,dg);
}
};
priority_queue<heap_node>q;
int vis[maxn+5];
int disrt[maxn+5];
int pre[maxn+5];
long long dijkstra(int s,int t){
memset(disrt,0x3f,sizeof(disrt));
disrt[s]=0;
q.push(heap_node(s,disrt[s]));
while(!q.empty()){
heap_node x=q.top();
q.pop();
if(vis[x.id]) continue;
vis[x.id]=1;
for(int i=head[x.id];i;i=E[i].next){
int y=E[i].to;
int tmprt;
T.insert(tmprt,disrt[x.id],E[i].len,0,dg);
if(disrt[y]==INF||T.cmp(tmprt,disrt[y],0,dg)){
disrt[y]=tmprt;
pre[y]=i;
q.push(heap_node(y,disrt[y]));
}
}
}
if(disrt[t]==INF) return -1;
else return T.tree[disrt[t]].sum;
} int cnt=0;
int res[maxn+5];
void get_ans(int s,int t){
int x=t;
while(x!=s){
res[++cnt]=x;
x=E[pre[x]].from;
}
res[++cnt]=x;
} int main(){
int u,v,w;
int s,t;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d %d %d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
dg=max(dg,w);
}
scanf("%d %d",&s,&t); dg+=log2(m)+1;//进位
pow2[0]=1;
for(int i=1;i<=dg;i++) pow2[i]=pow2[i-1]*2%mod; long long ans=dijkstra(s,t);
printf("%I64d\n",ans);
if(ans==-1) return 0; cnt=0;
get_ans(s,t);
printf("%d\n",cnt);
for(int i=cnt;i>=1;i--){
printf("%d ",res[i]);
}
}

[Codeforces 464E] The Classic Problem(可持久化线段树)的更多相关文章

  1. Codeforces 464E The Classic Problem (最短路 + 主席树 + hash)

    题意及思路 这个题加深了我对主席树的理解,是个好题.每次更新某个点的距离时,是以之前对这个点的插入操作形成的线段树为基础,在O(logn)的时间中造出了一颗新的线段树,相比直接创建n颗线段树更省时间. ...

  2. UOJ#77. A+B Problem [可持久化线段树优化建边 最小割]

    UOJ#77. A+B Problem 题意:自己看 接触过线段树优化建图后思路不难想,细节要处理好 乱建图无果后想到最小割 白色和黑色只能选一个,割掉一个就行了 之前选白色必须额外割掉一个p[i], ...

  3. 【BZOJ3218】a + b Problem 可持久化线段树优化建图

    [BZOJ3218]a + b Problem 题解:思路很简单,直接最小割.S->i,容量为Bi:i->T,容量为Wi:所有符合条件的j->new,容量inf:new->i, ...

  4. Codeforces 464E The Classic Problem(主席树+最短路+哈希,神仙题)

    题目链接 题意:给出一张 \(n\) 个点 \(m\) 条边的无向图,第 \(i\) 条边连接 \(u_i,v_i\),边权为 \(2^{w_i}\),求 \(s\) 到 \(t\) 的最短路. \( ...

  5. CodeForces 464E The Classic Problem | 呆克斯歘 主席树维护高精度

    题意描述 有一个\(n\)点\(m\)边的无向图,第\(i\)条边的边权是\(2^{a_i}\).求点\(s\)到点\(t\)的最短路长度(对\(10^9 + 7\)取模). 题解 思路很简单--用主 ...

  6. Codeforces 464E. The Classic Problem

    题目大意 给定一张$n$个点, $m$条边的无向图,求$S$ 到$T$的最短路,其中边权都是$2^k$的形式$n,m,k<=10^5$,结果对$10^9+7$取模 题解 大佬好厉害 跑一边dij ...

  7. BZOJ 3489 A simple rmq problem(可持久化线段树)

    题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3489 题意:一个数列.每次询问一个区间内出现一次的最大的数字是多少. 思路:设la ...

  8. BZOJ 3218 A + B Problem (可持久化线段树+最小割)

    做法见dalao博客 geng4512的博客, 思路就是用线段树上的结点来进行区间连边.因为有一个只能往前面连的限制,所以还要可持久化.(duliu) 一直以来我都是写dinicdinicdinic做 ...

  9. 主席树[可持久化线段树](hdu 2665 Kth number、SP 10628 Count on a tree、ZOJ 2112 Dynamic Rankings、codeforces 813E Army Creation、codeforces960F:Pathwalks )

    在今天三黑(恶意评分刷上去的那种)两紫的智推中,突然出现了P3834 [模板]可持久化线段树 1(主席树)就突然有了不详的预感2333 果然...然后我gg了!被大佬虐了! hdu 2665 Kth ...

随机推荐

  1. .NET Reactor使用教程(加密源代码示例)

    更多:https://www.cnblogs.com/PiaoMiaoGongZi/category/1120300.html 1.打开 Eziriz .NET Reactor,主界面如图1所示: 图 ...

  2. 日志远程更新脚本shell

    log_update.sh.bak: #!/bin/bash# To Update Logs... #/bin/rsync -avz --delete --exclude=warn.log @172. ...

  3. Linux 内核层和 用户层 配置 GPIO 引脚

    Linux BSP 开发的基础就是和GPIO打交道, 下面总结下这几天对某家开发板的GPIO控制的知识. 公司的开发板用的是 DTB  模式 ,首先,进入 dts,dtsi文件查看关于GPIO 的模块 ...

  4. JAVA 关于File的使用

    File中常用方法 创建 createNewFile() 在指定位置创建一个空文件,成功就返回true,如果已存在就不创建然后返回false mkdir() 在指定位置创建目录,这只会创建最后一级目录 ...

  5. eclipse没有Web项目和Server选项

    (1)在Eclipse中菜单help选项中选择install new software选项 (2)在work with 栏中输入 http://download.eclipse.org/release ...

  6. Redis 复制功能详解

    Redis 复制功能的几个重要方面: 1. 一个Master可以有多个Slave:2. Redis使用异步复制.从2.8版本开始,Slave会周期性(每秒一次)发起一个Ack确认复制流(replica ...

  7. java并发学习--第一章 线程的创建

    所谓的并发就是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行.所以我们看似几个线程在同时进行,其实在操作系统中 ...

  8. vue 自定义封装组件 使用 model 选项

    自定义组件的 v-model 一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框.复选框等类型的输入控件可能会将 value 特性用于不同 ...

  9. JUC并发工具类

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11449367.html java.util.concurrent及其子包,集中了Java并发的各种基础 ...

  10. [IOI2018] meetings 会议

    https://www.luogu.org/problemnew/show/P5044 题解 这种关于最大值或者最小值的问题,可以往笛卡尔树的方面想. 先考虑一个朴素的\(dp\),设\(dp[l][ ...