zoukankan      html  css  js  c++  java
  • 【SPOJ】10628. Count on a tree(lca+主席树+dfs序)

    http://www.spoj.com/problems/COT/

    (速度很快,排到了rank6)

    这题让我明白了人生T_T

    我知道我为什么那么sb了。

    调试一早上都在想人生。

    唉。

    太弱。

    太弱。

    手一抖,真的一生就毁了。

    不到一小时打好的代码,硬是调试了2小时。

    这什么水平。

    到头来,和network那题的错误一样,都是很逗的地方,上次漏打id,这次漏打root。

    调了一早上,无限吐槽一早上。差点让我以为自己人生没戏了。

    吐槽完毕。

    这题做法可以用树剖做,但是太麻烦。

    我是看了别人用主席树加lca做,速度很快,所以要来学习,并且还要为network那题的第二种做法打下基础,所以来写这题。

    我们dfs后,可以发现,每一个点到lca(不包括lca)都是在一个连续的区间,所以我们用主席树来维护每个点的到根的形态,用dfs序来维护。

    然后查找他们的路径u v就是查找 u到树根的主席树 和v到树根的主席树 和lca到树根的主席树 他们比k小的数量。然后做法和普通主席树一样。只不过 s=s(lson[u])+s(lson[v])-2*s(lson[lca]),如果lca本身在区间[l, m]内,s还要加上1,这个自己去领悟,我倒是领悟了一段时间的。

    坑爹的属性我在代码里标记了,一定要铭记,千万以后不要犯这种sb错!!!!!

    FIGHT!!!!!!!!!!!!!!!!!!!!!!!!!!!

    (代码其实很短的,lca我用tarjan做,离线)

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    #define MID (l+r)>>1
    #define dbg(x) cout << #x << " = " << x << endl
    #define read(x) x=getint()
    #define rdm(x) for(int i=ihead[x]; i; i=e[i].next)
    inline const int getint() { char c=getchar(); int k=1, ret=0; for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret*k; }
    const int N=100005;
    struct ed { int to, next; } e[N<<1];
    struct ND { int l, r, s; } t[N*20];
    int ihead[N], cnt, num, lca[N], fa[N], p[N], a[N], b[N], k[N], id[N], root[N], u[N], v[N], n, m, ff;
    bool vis[N];
    vector<pair<int, int> > q[N];
    inline void add(const int &u, const int &v) {
    	e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v;
    	e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u;
    }
    void update(const int &l, const int &r, int &pos) {
    	t[++num]=t[pos]; pos=num; ++t[pos].s;
    	if(l==r) return;
    	int m=MID;
    	if(ff<=m) update(l, m, t[pos].l); else update(m+1, r, t[pos].r);
    }
    int ifind(const int &x) { return x==p[x]?x:p[x]=ifind(p[x]); }
    void dfs(const int &x) {
    	p[x]=x; root[x]=root[fa[x]]; ff=b[x]; update(1, n, root[x]);
    	rdm(x) if(e[i].to!=fa[x]) { fa[e[i].to]=x; dfs(e[i].to); p[e[i].to]=x; }
    	vis[x]=1;
    	int t=q[x].size();
    	for(int i=0; i<t; ++i) if(vis[q[x][i].first]) lca[q[x][i].second]=ifind(q[x][i].first);
    }
    int getans(const int &l, const int &r, const int &x, const int &y, const int &f, const int &key) {
    	if(l==r) return l;
    	int m=MID, s=t[t[x].l].s + t[t[y].l].s - (t[t[f].l].s << 1);
    	if(b[ff]>=l && b[ff]<=m) ++s; //这里要注意,lca是减掉了的,所以还要判断合法性
    	if(key<=s) return getans(l, m, t[x].l, t[y].l, t[f].l, key);
    	else return getans(m+1, r, t[x].r, t[y].r, t[f].r, key-s);
    }
    bool cmp(const int &x, const int &y) { return a[x]<a[y]; }
    int main() {
    	read(n); read(m);
    	for(int i=1; i<=n; ++i) read(a[i]), id[i]=i;
    	sort(id+1, id+1+n, cmp);
    	for(int i=1; i<=n; ++i) b[id[i]]=i;
    	for(int i=1; i<n; ++i) add(getint(), getint());
    	for(int i=1; i<=m; ++i) {
    		read(u[i]); read(v[i]); read(k[i]);
    		q[u[i]].push_back(pair<int, int> (v[i], i));
    		q[v[i]].push_back(pair<int, int> (u[i], i));
    	}
    	dfs(1);
    	for(int i=1; i<=m; ++i) {
    		if(u[i]==v[i]) { printf("%d
    ", a[u[i]]); continue; }
    		ff=lca[i];
    		printf("%d
    ", a[id[getans(1, n, root[u[i]], root[v[i]], root[ff], k[i])]]); //被root[ff]坑了一早上,写成了ff。唉
    	}
    	return 0;
    }
    

    You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight.

    We will ask you to perform the following operation:

    • u v k : ask for the kth minimum weight on the path from node u to node v

    Input

    In the first line there are two integers N and M.(N,M<=100000)

    In the second line there are N integers.The ith integer denotes the weight of the ith node.

    In the next N-1 lines,each line contains two integers u v,which describes an edge (u,v).

    In the next M lines,each line contains three integers u v k,which means an operation asking for the kth minimum weight on the path from node u to node v.

    Output

    For each operation,print its result.

    Example

    Input:
    8 5
    8 5
    105 2 9 3 8 5 7 7
    1 2        
    1 3
    1 4
    3 5
    3 6
    3 7
    4 8
    2 5 1
    2 5 2
    2 5 3
    2 5 4
    7 8 2 
    Output:
    2
    8
    9
    105
    7
  • 相关阅读:
    Reverse Integer
    Same Tree
    BST(Binary Search Tree)
    Maximum Depth of Binary Tree
    Single Number
    Computer System Basic Concept(2)
    破解企业QQ对个人QQ登陆的限制(原创)
    鸟哥的Linux私房菜.基础学习篇(摘要)(持续更新)
    Linux系列书籍
    【总结】关于彩虹表学习阶段性总结
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/3929098.html
Copyright © 2011-2022 走看看