题解 最短路
首先容易得到一个高精的做法
但是复杂度显然不对
发现这里的加法较为特别,每次要加的数中一定只有一位是1
所以可以放到线段树上做加法和比较
加法的话线段树上二分出下一个为 0 的位置,然后将需要覆盖掉的一段 1 都置零即可
比较的话发现结果一定在最高不同位取到
所以可以维护一个hash值,用来判断右儿子中有没有不同位
这些整合起来可以用主席树实现
但是动态开点的时候因为查询也需要下传标记,所以空间会炸
- 一种只有区间覆盖且值域和下标范围均较小(例:只有区间0/1覆盖)的动态开点线段树的时间/空间优化方法:
对值域中的每种值开一棵满的线段树,区间覆盖时直接将目标区间替换成这棵树上的对应节点即可
于是可以通过,时间复杂度 ,空间复杂度
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200060
#define LIM 200050
//#define LIM 8
#define fir first
#define sec second
#define ll long long
#define ull unsigned long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m, s, t;
int head[N], ecnt;
const ll mod=1e9+7;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}
// namespace force{
// bool vis[N];
// ll dis[N];
// priority_queue<pair<ll, int>> q;
// struct edge{int to, next; ll val;}e[N<<1];
// inline void add(int s, int t, ll w) {e[++ecnt]={t, head[s], w}; head[s]=ecnt;}
// ll dij(int s, int t) {
// memset(dis, 127, sizeof(dis));
// dis[s]=0;
// q.push({0, s});
// while (q.size()) {
// pair<ll, int> u=q.top(); q.pop();
// if (vis[u.sec]) continue;
// vis[u.sec]=1;
// for (int i=head[u.sec],v; ~i; i=e[i].next) {
// v = e[i].to;
// if (dis[u.sec]+e[i].val < dis[v]) {
// dis[v]=dis[u.sec]+e[i].val;
// q.push({-dis[v], v});
// }
// }
// }
// return dis[t];
// }
// void solve() {
// for (int i=1,u,v,x; i<=m; ++i) {
// u=read(); v=read(); x=read();
// add(u, v, 1ll<<x); add(v, u, 1ll<<x);
// }
// s=read(); t=read();
// printf("%lld\n", dij(s, t)%mod);
// }
// }
// namespace task1{
// bool vis[N];
// struct bigint{
// char a[251];
// bigint(){memset(a, 0, sizeof(a));}
// bigint(ll w) {memset(a, 0, sizeof(a)); a[w]=1;}
// inline char& operator [] (int t) {return a[t];}
// void setinf() {for (int i=0; i<251; ++i) a[i]=1;}
// inline bigint operator + (bigint b) {
// bigint ans;
// for (int i=0; i<250; ++i) {
// ans[i]+=a[i]+b[i];
// ans[i+1]+=ans[i]>>1;
// ans[i]&=1;
// }
// return ans;
// }
// ll toll() {
// ll ans=0;
// for (int i=0; i<251; ++i) if (a[i]) ans=(ans+qpow(2, i))%mod;
// return ans;
// }
// }dis[N];
// inline bool operator < (bigint a, bigint b) {
// for (int i=250; ~i; --i) if (a[i]!=b[i]) return a[i]<b[i];
// return 0;
// }
// priority_queue<pair<bigint, int>, vector<pair<bigint, int>>, greater<pair<bigint, int>>> q;
// struct edge{int to, next; bigint val;}e[N<<1];
// inline void add(int s, int t, ll w) {e[++ecnt]={t, head[s], bigint(w)}; head[s]=ecnt;}
// bigint dij(int s, int t) {
// for (int i=1; i<=n; ++i) if (i!=s) dis[i].setinf();
// q.push({dis[s], s});
// while (q.size()) {
// pair<bigint, int> u=q.top(); q.pop();
// if (vis[u.sec]) continue;
// vis[u.sec]=1;
// for (int i=head[u.sec],v; ~i; i=e[i].next) {
// v = e[i].to;
// if (dis[u.sec]+e[i].val < dis[v]) {
// dis[v]=dis[u.sec]+e[i].val;
// q.push({dis[v], v});
// }
// }
// }
// return dis[t];
// }
// void solve() {
// for (int i=1,u,v,x; i<=m; ++i) {
// u=read(); v=read(); x=read();
// add(u, v, x); add(v, u, x);
// }
// s=read(); t=read();
// printf("%lld\n", dij(s, t).toll());
// }
// }
namespace task{
bool vis[N];
ull val[N*150], pw[N];
const ull base=13131;
int lson[N*150], rson[N*150], dsu[N], rot0, rot1, tot;
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
#define val(p) val[p]
#define ls(p) lson[p]
#define rs(p) rson[p]
#define pushup(p) val(p)=val(ls(p))+val(rs(p))*pw[mid-tl+1]
void build(int& p, int tl, int tr, int dat) {
p=++tot;
if (tl==tr) {val(p)=dat; return ;}
int mid=(tl+tr)>>1;
if (tl<=mid) build(ls(p), tl, mid, dat);
if (tr>mid) build(rs(p), mid+1, tr, dat);
pushup(p);
}
void upd(int& p1, int p2, int tl, int tr, int ql, int qr) {
++tot; val(tot)=val(p1); ls(tot)=ls(p1); rs(tot)=rs(p1); p1=tot;
if (ql<=tl&&qr>=tr) {val(p1)=val(p2); ls(p1)=ls(p2); rs(p1)=rs(p2); return ;}
int mid=(tl+tr)>>1;
if (ql<=mid) upd(ls(p1), ls(p2), tl, mid, ql, qr);
if (qr>mid) upd(rs(p1), rs(p2), mid+1, tr, ql, qr);
pushup(p1);
}
ll tran(int p, int tl, int tr) {
if (!p) return 0;
if (tl==tr) return val(p);
int mid=(tl+tr)>>1;
return (tran(ls(p), tl, mid)+tran(rs(p), mid+1, tr)*qpow(2, mid-tl+1))%mod;
}
void show(int p, int tl, int tr) {
if (tl==tr) {cout<<val(p)<<' '; return ;}
int mid=(tl+tr)>>1;
show(ls(p), tl, mid); show(rs(p), mid+1, tr);
if (tl==1 && tr==LIM) cout<<endl;
}
bool isless(int p1, int p2, int tl, int tr) {
// cout<<"isless: "<<p1<<' '<<p2<<' '<<tl<<' '<<tr<<endl;
if (tl==tr) return val(p1)<val(p2);
if (val(p1)==val(p2)) return 0;
int mid=(tl+tr)>>1;
if (val(rs(p1))!=val(rs(p2))) return isless(rs(p1), rs(p2), mid+1, tr);
else return isless(ls(p1), ls(p2), tl, mid);
}
int findnxt(int p, int tl, int tr, int pos) {
if (tl==tr) return val(p)?-1:tl;
int mid=(tl+tr)>>1;
if (pos<=mid) {
int tem=findnxt(ls(p), tl, mid, pos);
if (~tem) return tem;
}
return findnxt(rs(p), mid+1, tr, pos);
}
struct bigint{
int rot;
void add(int w) {
int nxt=findnxt(rot, 0, LIM, w);
if (nxt!=w) upd(rot, rot0, 0, LIM, w, nxt-1);
upd(rot, rot1, 0, LIM, nxt, nxt);
}
void show() {task::show(rot, 0, LIM);}
ll toll() {return tran(rot, 0, LIM)%mod;}
}dis[N], tem;
inline bigint operator + (bigint a, int b) {bigint ans=a; ans.add(b); return ans;}
inline bool operator < (bigint a, bigint b) {return isless(a.rot, b.rot, 1, LIM);}
priority_queue<pair<bigint, int>, vector<pair<bigint, int>>, greater<pair<bigint, int>>> q;
struct edge{int to, next, val;}e[N<<1];
inline void add(int s, int t, int w) {e[++ecnt]={t, head[s], w}; head[s]=ecnt;}
bigint dij(int s, int t) {
for (int i=1; i<=n; ++i) dis[i].rot=(i==s)?rot0:rot1;
q.push({dis[s], s});
while (q.size()) {
pair<bigint, int> u=q.top(); q.pop();
if (vis[u.sec]) continue;
vis[u.sec]=1;
for (int i=head[u.sec],v; ~i; i=e[i].next) {
v = e[i].to;
if (dis[u.sec]+e[i].val < dis[v]) {
dis[v]=dis[u.sec]+e[i].val;
q.push({dis[v], v});
}
}
}
return dis[t];
}
void solve() {
// cout<<double(sizeof(e)+sizeof(dis)+sizeof(val)+sizeof(lson)*2+sizeof(pw))/1000/1000<<endl;
pw[0]=1;
for (int i=1; i<=LIM; ++i) pw[i]=pw[i-1]*base;
build(rot0, 0, LIM, 0);
build(rot1, 0, LIM, 1);
for (int i=1; i<=n; ++i) dsu[i]=i;
for (int i=1,u,v,x; i<=m; ++i) {
u=read(); v=read(); x=read();
add(u, v, x); add(v, u, x);
if (find(u)!=find(v)) dsu[find(u)]=find(v);
}
s=read(); t=read();
if (find(s)!=find(t)) puts("-1");
else printf("%lld\n", dij(s, t).toll());
}
}
signed main()
{
freopen("hellagur.in", "r", stdin);
freopen("hellagur.out", "w", stdout);
n=read(); m=read();
memset(head, -1, sizeof(head));
//force::solve();
task::solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!