NOI2018归程

Problem

传送门

给一张图,每条边有两个参数:(w,h),分别代表边长与海拔

有Q个询问,每次询问从给定点出发,借助一辆只能走海拔大于h的边的车后,到一号点最短步行的距离。

Solution

正解是(kruskal)重构树,很好理解,也很好打,网上题解很多,这里就不讲了

下面我们讲一下一个需吸氧且随缘(T)点的做法

可持久化并查集

有没有感觉十分高端大气上档次?

表示没有

之前上网看过这中算法,但是一直没有看懂

右边大佬这个是怎么实现的

结果

右边大佬:啊?……不就是可持久化那样搞一下……按质合并……就可以了吗?

(caiji)表示听不懂……

后来跑到隔壁的时候(Na_2S_2O_3 zbr)提了一嘴

(Na_2S_2O_3):你别(fake)

(caiji):我是真不会

(zbr):啊?就是拿个可持久化数组维护一下并查集就可以了啊

(caiji):可持久化数组是什么?

(Na_2S_2O_3):就是用主席树维护一个数组啊……

(恍然大雾.jpg)

咳咳,跑题了。

现在来讲一讲这道题

先考虑离线,就是先跑一边最短路

询问与边都按从大到小排序,然后每次询问倒序进去的时候按比海拔高的约束加入能开车的边,

这个东西可以用并查集维护。

每次维护这个联通块中到一号点的最小距离,直接输出就好了。

接下来就是在线了

某位伟大的博士曾说过

勇矢博士:所有可离线做的问题都可以用可持久化数据结构在线做。

好像很有道理……

所以我们这道题可以用可持久化并查集……

对于每个询问,我们只需回到没有添加海拔比(q)小的路的版本,再查询(v)所在的联通块即可

复杂度(O(n(logn)^2))

卡卡常,好像能过个鬼

拷了个海波的快输还是T了两点

Code

#include<bits/stdc++.h>
#define mp make_pair
#define fst first
#define snd second
#define LL long long
#define pli pair<LL,int>
#define pii pair<int,int>

using namespace std;

inline int read(){
	int res = 0, fl = 1;
	char r = getchar();
	for (; !isdigit(r); r = getchar()) if(r == '-') fl = -1;
	for (; isdigit(r); r = getchar()) res = (res << 3) + (res << 1) + r - 48;
	return res * fl;
}

char _obuf[1 << 20], _stk[20];
class Ostream
{
    char *opos, *oend, *stkpos;

public :
    Ostream()
    {
        oend = (opos = _obuf) + (1 << 20);
        stkpos = _stk;
    }

    ~Ostream()
    { fwrite(_obuf, 1, opos - _obuf, stdout); }

    void Putchar(char ch)
    {
        *opos++ = ch;
        if(opos == oend)
        {
            fwrite(_obuf, 1, 1 << 20, stdout);
            opos = _obuf;
        }
    }

    Ostream& operator<<(int n)
    {
        do
        {
            *++stkpos = n % 10 ^ 48;
            n /= 10;
        } while(n);
        while(stkpos != _stk)
            Putchar(*stkpos--);
        return *this;
    }

    Ostream& operator<<(char c)
    {
        Putchar(c);
        return *this;
    }

    Ostream& operator<<(const char* str)
    {
        while(*str != '')
            Putchar(*str++);
        return *this;
    }
} out;

inline void chkmin(int &A, int &B) { A = min(A, B);}
inline void chkmax(int &A, int &B) { A = max(A, B);}

const int Maxm = 4e5 + 10, Maxn = 2e5 + 10;

vector <pii> g[Maxn];

struct node{
	int u, v, h;
	bool operator < (const node A) const{ return h > A.h;}
}Map[Maxm];

int n, m, Q, K, S, ans;
int root[Maxn], dis[Maxn];

namespace CMT{
#define mid ((l + r) >> 1)
	int ls[Maxn << 6], rs[Maxn << 6], cnt, root[Maxm << 2], Tim;
	struct TRE{
		int fa, siz, dis;
	}tre[Maxn << 6];
	inline void build(int &rt, int l, int r){
		rt = ++cnt;
		if(l == r) {tre[rt].fa = l, tre[rt].siz = 1, tre[rt].dis = dis[l]; return;}
		build(ls[rt], l, mid);
		build(rs[rt], mid + 1, r);
	}
	inline void Init(){ cnt = 0; build(root[1], 1, n); Tim = 0;}
	inline int Query(int Begin, int rt, int l, int r, int pos){
		if(l == r){return tre[rt].fa == l ? rt : Query(Begin, Begin, 1, n, tre[rt].fa);}
		if(mid >= pos) return Query(Begin, ls[rt], l, mid, pos);
		else return Query(Begin, rs[rt], mid + 1, r, pos);
	}
	inline void Modify_fa(int grt, int &rt, int l, int r, int pos, int fa){
		rt = ++cnt, ls[rt] = ls[grt], rs[rt] = rs[grt], tre[rt] = tre[grt];
		if(l == r) { tre[rt].fa = fa; return;}
		if(mid >= pos) Modify_fa(ls[grt], ls[rt], l, mid, pos, fa);
		else Modify_fa(rs[grt], rs[rt], mid + 1, r, pos, fa);
	}
	inline void Modify(int grt, int &rt, int l, int r, int pos, int siz, int Dis){
		rt = ++cnt, ls[rt] = ls[grt], rs[rt] = rs[grt], tre[rt] = tre[grt];
		if(l == r){
			tre[rt].siz += siz, chkmin(tre[rt].dis, Dis);
			return;
		}
		if(mid >= pos) Modify(ls[grt], ls[rt], l, mid, pos, siz, Dis);
		else Modify(rs[grt], rs[rt], mid + 1, r, pos, siz, Dis);
	}
	inline int link(int u, int v){
		register int rfu = Query(root[Tim << 1 | 1], root[Tim << 1 | 1], 1, n, u);
		register int rfv = Query(root[Tim << 1 | 1], root[Tim << 1 | 1], 1, n, v);
		if(tre[rfu].fa == tre[rfv].fa) return 0;
		Tim++;
		if(tre[rfu].siz > tre[rfv].siz) swap(rfu, rfv);
		Modify_fa(root[(Tim << 1) - 1], root[Tim << 1], 1, n, tre[rfu].fa, tre[rfv].fa);
		Modify(root[Tim << 1], root[Tim << 1 | 1], 1, n, tre[rfv].fa, tre[rfu].siz, tre[rfu].dis);
		return Tim << 1 | 1;
	}
	inline LL Query_dis(int Time, int v){
		return tre[Query(root[Time], root[Time], 1, n, v)].dis;
	}
#undef mid
}

bitset<Maxn> vis, clean;

inline void dijstra(){
	priority_queue <pii> Q;
	memset(dis, 0x3f, sizeof dis);
	vis = clean;
	Q.push(mp(0, 1));
	dis[1] = 0;
	while(!Q.empty()){
		register int now = Q.top().snd;
		Q.pop();
		if(vis[now]) continue;
		vis[now] = 1;
		for (register int i = g[now].size() - 1; i >= 0; --i){
			register int nxt = g[now][i].fst;
			if(dis[nxt] > dis[now] + g[now][i].snd)
				dis[nxt] = dis[now] + g[now][i].snd,
				Q.push(mp(-dis[nxt], nxt));
		}
	}
}
set<pii> Tim;
inline void work(int &T){
	n = read(), m = read(), ans = 0;
	for (register int i = 1; i <= m; ++i){
		register int u = read(), v = read(), w = read(), h = read();
		Map[i] = (node){u, v, h};
		g[u].push_back(mp(v, w));
		g[v].push_back(mp(u, w));
	}
	dijstra();
	sort(Map + 1, Map + 1 + m);
	CMT::Init();
	for (register int i = 1; i <= m; ++i){
		register int u = Map[i].u, v = Map[i].v;
		register int TIME = CMT::link(u, v);
		if(TIME)
			Tim.insert(mp(Map[i].h, -TIME));
	}
	Q = read(), K = read(), S = read();
	Tim.insert(mp(S + 1, -1));
	Tim.insert(mp(0, -(CMT::Tim << 1 | 1)));
	while(Q--){
		register int v = ((LL)read() + K * ans - 1) % n + 1;
		register int p = ((LL)read() + K * ans) % (S + 1);
		pii Time = *Tim.upper_bound(mp(p, 1e9));
		ans = CMT::Query_dis(-Time.snd, v);
		out << ans << '
';
	}
	if(T) Tim.clear();
	if(T) for (register int i = 1; i <= n; ++i) g[i].clear();
}
int main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	int T = read();
	while(T--) work(T);
	return 0;
}
原文地址:https://www.cnblogs.com/LZYcaiji/p/10622087.html