题解 最短路

传送门

首先容易得到一个高精的做法
但是复杂度显然不对
发现这里的加法较为特别,每次要加的数中一定只有一位是1
所以可以放到线段树上做加法和比较
加法的话线段树上二分出下一个为 0 的位置,然后将需要覆盖掉的一段 1 都置零即可
比较的话发现结果一定在最高不同位取到
所以可以维护一个hash值,用来判断右儿子中有没有不同位
这些整合起来可以用主席树实现
但是动态开点的时候因为查询也需要下传标记,所以空间会炸

  • 一种只有区间覆盖且值域和下标范围均较小(例:只有区间0/1覆盖)的动态开点线段树的时间/空间优化方法:
    对值域中的每种值开一棵满的线段树,区间覆盖时直接将目标区间替换成这棵树上的对应节点即可

于是可以通过,时间复杂度 \(O(n\log^2 n)\),空间复杂度 \(O(n\log n)\)

点击查看代码
#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;
}
posted @ 2022-02-19 15:36  Administrator-09  阅读(1)  评论(0编辑  收藏  举报