zoukankan      html  css  js  c++  java
  • Codeforces 464E The Classic Problem (最短路 + 主席树 + hash)

    题意及思路

    这个题加深了我对主席树的理解,是个好题。每次更新某个点的距离时,是以之前对这个点的插入操作形成的线段树为基础,在O(logn)的时间中造出了一颗新的线段树,相比直接创建n颗线段树更省时间。比较的时候二分比较,为了加快比较给每个点设置一个hash值。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const unsigned long long P = 13331;
    const int mod = 1000000007;
    const int maxn = 100010;
    
    int head[maxn], Next[maxn * 2], edge[maxn * 2], ver[maxn * 2];
    int tot, tote;
    int b[maxn * 2], pre[maxn];
    int mx, dis[maxn];
    bool vis[maxn];
    int Stack[maxn], Top;
    
    void add(int x, int y, int z) {
    	ver[++tote] = y;
    	edge[tote] = z;
    	Next[tote] = head[x];
    	head[x] = tote;
    }
    struct SegementTree {
    	int ls, rs;
    	int sum;
    	unsigned long long hash;
    }tr[maxn * 200];
    
    void pushup(int x) {
    	tr[x].sum = tr[tr[x].ls].sum + tr[tr[x].rs].sum;
    	unsigned long long tmp1 = tr[tr[x].ls].hash, tmp2 = tr[tr[x].rs].hash;
    	tr[x].hash = (((tmp1 * P + tmp2) ^ tmp1) * P ^ tmp2) * P;
    }
    
    void insert(int &now, int l, int r, int pos) {
    	int p = now;
    	now = ++tot;
    	tr[now] = tr[p];
    	if(l == r) {
    		tr[now].sum = 1;
    		tr[now].hash = l + P;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(pos <=  mid)  insert(tr[now].ls, l, mid, pos);
    	else insert(tr[now].rs, mid + 1, r, pos);
    	pushup(now);
    }
    
    void del(int &now, int l, int r, int ql, int qr) {
    	if(l >= ql && r <= qr) {
    		now = 0;
    		return;
    	}
    	int p = now;now = ++tot;
    	tr[now] = tr[p];
    	int mid = (l + r) >> 1;
    	if(ql <= mid) del(tr[now].ls, l, mid, ql, qr);
    	if(qr > mid) del(tr[now].rs, mid + 1, r, ql, qr);
    	pushup(now);
    }
    
    int query(int now, int l, int r, int pos) {
    	if(l == r) {
    		if(tr[now].sum == 0) return l;
    		return -1;
    	}
    	int mid = (l + r) >> 1;
    	if(pos > mid) return query(tr[now].rs, mid + 1, r, pos);
    	int ans = query(tr[now].ls, l, mid, pos);
    	if(ans != -1) return ans;
    	return query(tr[now].rs, mid + 1, r, pos);
    }
    
    int add(int now, int pos) {
    	int p = query(now, 0, mx, pos);
    	if(p > pos) del(now, 0, mx, pos, p - 1);
    	insert(now, 0, mx, p);
    	return now;
    }
    
    int get_sum(int now, int l, int r) {
    	int mid = (l + r) >> 1;
    	if(now == 0) return 0;
    	if(l == r) return b[l];
    	return (get_sum(tr[now].ls, l, mid) + get_sum(tr[now].rs, mid + 1, r)) % mod;
    }
    
    bool cmp(int x, int y, int l, int r) {
    	if(l == r) return tr[x].sum >= tr[y].sum;
    	int mid = (l + r) >> 1;
    	if(tr[tr[x].rs].hash != tr[tr[y].rs].hash) 
    		return cmp(tr[x].rs, tr[y].rs, mid + 1, r);
    	else return cmp(tr[x].ls, tr[y].ls, l, mid);
    }
    
    struct node {
    	int x, y;
    	bool operator < (const node& rhs) const {
    		return cmp(x, rhs.x, 0, mx);
    	}
    };
    
    priority_queue<node> q;
    
    void dijkstra(int s) {
    	dis[s] = ++tot, q.push((node){dis[s], s});
    	while(!q.empty()) {
    		node tmp = q.top();
    		q.pop();
    		if(vis[tmp.y]) continue;
    		vis[tmp.y] = 1;
    		int x = tmp.y;
    		for (int i = head[x]; i; i = Next[i]) {
    			int y = ver[i], z = add(dis[x], edge[i]);
    			if(!dis[y] || !cmp(z, dis[y], 0, mx)) {
    				pre[y] = x;
    				dis[y] = z;
    				q.push((node){z, y});
    			}
    		}
    	}
    }
    
    void print(int x, int deep) {
    	if(x == 0) {
    		printf("%d
    ", deep);
    		return;
    	} 
    	print(pre[x], deep + 1);
    	printf("%d ", x);
    }
    int main() {
    	int n, m, x, y, z, s, t;
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= m; i++) {
    		scanf("%d%d%d", &x, &y, &z);
    		add(x, y, z);
    		add(y, x, z);
    		mx = max(mx, z);
    	}
    	b[0] = 1;
    	mx += 20;
    	for (int i = 1; i <= mx; i++) {
    		b[i] = (b[i - 1] << 1) % mod;
    	}
    	scanf("%d%d", &s, &t);
    	dijkstra(s);
    	if(dis[t] == 0) printf("-1
    ");
    	else {
    		printf("%d
    ", get_sum(dis[t], 0, mx));
    		while(t) {
    			Stack[++Top] = t;
    			t = pre[t];
    		}
    		printf("%d
    ", Top);
    		while(Top) {
    			printf("%d ", Stack[Top]);
    			Top--;
    		}
    	}
    }
    

      

  • 相关阅读:
    Docker-compose部署Elasticsearch+Kibana+Filebeat+APM(7.13.2)
    容器和镜像转化、迁移方式
    Docker部署redis主从+读写分离+哨兵
    简单的Redis及哨兵监控报警
    Prometheus监控docker容器
    Jenkins---多选参数构建
    Nginx——基于站点目录和文件的URL访问控制、禁止IP/非法域名访问
    Docker-compose构建jenkins环境
    Docker部署kafka集群
    Goreplay-使用真实流量测试
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10566988.html
Copyright © 2011-2022 走看看