zoukankan      html  css  js  c++  java
  • [ONTAK2010]Peaks

    [ONTAK2010]Peaks
    Time Limit: 10 Sec Memory Limit: 128 MB
    在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,
    每条路径有一个困难值,这个值越大表示越难走,
    现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,
    如果无解输出-1。

    Input

    第一行三个数N,M,Q。
    第二行N个数,第i个数为h_i
    接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
    接下来Q行,每行三个数v x k,表示一组询问。
    N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。

    Output
    对于每组询问,输出一个整数表示答案。

    Sample Input
    10 11 4
    1 2 3 4 5 6 7 8 9 10
    1 4 4
    2 5 3
    9 8 2
    7 8 10
    7 1 4
    6 7 1
    6 4 8
    2 1 5
    10 8 10
    3 4 7
    3 4 6
    1 5 2
    1 5 6
    1 5 8
    8 9 2

    Sample Output
    6
    1
    -1
    8

    /*
    Sol:此题方法有很多,可以线段树合并,可以重构树+主席树+Dfs.
    针对原图做个重构树,大根堆的。
    新建出来的点的权值为其所连的两个点的从前的边权即困难值 
    于是我们可以从一个点向上跳,只要所跳的点困难值<=所给的值,就可以跳.
    跳到指定点后,它所在的树所包括的所有结点,我们就可以求第K大了。
    这个用dfs序搞出来就好了。 
    */
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define N 200005
    #define M 500005
    struct node{int x, y, v;}S[M];
    struct node2{int l, r, v;}A[N * 20];
    bool cmp(node a, node b){return a.v < b.v;}
    int num, tot, res, n, m, t, h[N], bel[N], T[N];
    int f[N][25], dep[N], val[N], out[N], ins[N], hgt[N];
    int tar[M], nex[M], fir[N], cnt;
    void Read(int &p)
    {
    	p = 0;
    	char c = getchar();
    	for (; c < '0' || c > '9'; c = getchar());
    	for (; c >= '0' && c <= '9'; c = getchar())p = p * 10 + c - '0';
    }
    void Add(int x, int y)
    {
    	++cnt;
    	tar[cnt] = y;
    	nex[cnt] = fir[x];
    	fir[x] = cnt;
    }
    int Getbel(int x)
    {
    	if (!bel[x])
    		return x;
    	return bel[x] = Getbel(bel[x]);
    }
    int Query(int x, int v)
    {
    	for (int i = 20; i >= 0; i--)
    		if (f[x][i] && val[f[x][i]] <= v)
    		//只要所跳的点小于等于v时就可以跳到这个点 
    			x = f[x][i];
    	return x;
    }
    void Insert(int &q, int l, int r, int v)
    {
    	A[++num] = A[q];
    	q = num;
    	A[q].v++;
    	if (l == r)
    		return;
    	int mid = (l + r) >> 1;
    	if (v <= mid)
    		Insert(A[q].l, l, mid, v);
    	else
    		Insert(A[q].r, mid + 1, r, v);
    }
    int Getans(int x, int k, int l, int r, int v)
    //x开始时间
    //k结束时间
    //l,r左右边界
    //找第v大 
    {
    	if (l == r)
    		return l;
    	int mid = (l + r) >> 1, pos = A[A[k].l].v - A[A[x].l].v;
    	if (v <= pos)
    		return Getans(A[x].l, A[k].l, l, mid, v);
    	return Getans(A[x].r, A[k].r, mid + 1, r, v - pos);
    }
    void Dfs(int x)
    {
    	if (x <= n)
    		h[++tot] = hgt[x];
    	ins[x] = tot;//dfs序, ins是x的进入时间 
    	for (int i = 1; i <= 20; i++)
    		f[x][i] = f[f[x][i - 1]][i - 1];
    	for (int i = fir[x]; i; i = nex[i])
    	{
    		int v = tar[i];
    		f[v][0] = x;
    		dep[v] = dep[x] + 1;
    		Dfs(v);
    	}
    	out[x] = tot;//out是x的出去时间 
    }
    void Build()
    {
    	res = n;//总结点个数 
    	sort(S + 1, S + m + 1, cmp);//边权排序 
    	for (int i = 1; i <= m; i++)
    	{
            int u = Getbel(S[i].x), v = Getbel(S[i].y);
            //并查集找出父亲点 
            if (u != v)
    		{
    			val[++res] = S[i].v;
    			bel[u] = bel[v] = res;
    			Add(res, u), Add(res, v);
    		}
    	}
    }
    void Solve()
    {
        int last = -1;
    	while (t--)
    	{
    		int v, x, k;
    		Read(v), Read(x), Read(k);
    		//if (last != -1)
    		//	v ^= last, x ^= last, k ^= last;
    		int now = Query(v, x); //从v点向上跳距离不超过x时,能跳到哪个点去 
    	    if(out[now] - ins[now] < k) //如果以x为根的树结点总个数小于k则无解 
    		   last = -1 ;
    		else
    		    last = hgt[Getans(T[ins[now]], T[out[now]], 1, n, out[now] - ins[now] - k + 1)];
    		printf("%d
    ", last);
        }
    }
    int main()
    {
    	Read(n), Read(m), Read(t);
    	for (int i = 1; i <= n; i++)
    		Read(hgt[i]);
    	for (int i = 1; i <= m; i++) 
    		Read(S[i].x), Read(S[i].y), Read(S[i].v);
    	Build();//重构树 
    	Dfs(Getbel(1));
        sort(hgt + 1, hgt + n + 1);
    	int k = unique(hgt + 1, hgt + n + 1) - hgt - 1;
    	//离散化 
    	for (int i = 1; i <= n; i++)
    	{
    		T[i] = T[i - 1];
    		Insert(T[i], 1, k, lower_bound(hgt + 1, hgt + k + 1, h[i]) - hgt);
    		//将各点高度加入到主席树中 
    	}
    	n = k;
    	Solve();
    }
    

      

  • 相关阅读:
    归并排序
    CTE 递归
    Cordova 入门文档
    Javascript 原型链
    Windows11 正式版偷渡开启安卓子系统
    快速解决gerrit merge confict问题
    利用VPS来搭建个人主页
    检测串行序列10010
    Verilog语法总结
    深度学习中常见优化算法学习笔记
  • 原文地址:https://www.cnblogs.com/cutemush/p/11791397.html
Copyright © 2011-2022 走看看