zoukankan      html  css  js  c++  java
  • [CF1110F] Nearest Leaf

    Portal

    一棵n个点的有根树,规定一种dfs序,(m)次询问一个点(u)和一个区间([l,r]),求dfs序在这个区间内的叶子中,到(u)最小的距离。

    n,m≤500000

    这题在线直接搞很难搞, 考虑离线.

    一开始想到就是按照区间来离线, 把询问挂在某个端点上. 但是没有什么可以利用的性质(比如说要求单调可以单调队列), 所以弃掉.

    考虑按照询问点来离线,然后考虑一每条边的贡献, 若果进入了这条边, 那么到外面的距离会增加, 里面的部分会减少. 这样直接用线段树维护就可以了, 实现有点麻烦.

    考虑这个问题的扩展, 如果要在线, 考虑主席树(参照CF893F), 对于求某一点到树上某一dfn区间的题目也可以这样离线做(参照BZOJ2159,Crash的文明世界),(HDU5449 RobotDog,还是有点像的).

    离线题目就可以应用换根的思想, 利用已经计算的值快速计算其他值, 做树上题目一定要注意这点(*).

    说那么多干什么, 不就是暴力么?

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
    #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
    #define clar(a, b) memset((a), (b), sizeof(a))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    #define Debug(s) debug("The massage in line %d, Function %s: %s
    ", __LINE__, __FUNCTION__, s)
    typedef long long LL;
    typedef long double LD;
    int read() {
        char ch = getchar();
        int x = 0, flag = 1;
        for(;!isdigit(ch); ch = getchar()) if(ch == '-') flag *= -1;
        for(;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
        return x * flag;
    }
    void write(LL x) {
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar(x % 10 + 48);
    }
    
    const int Maxn = 500009;
    struct edge {
    	int to, nxt, w;
    }g[Maxn << 2];
    int n, q, head[Maxn], e;
    LL dis[Maxn], isleaf[Maxn], ans[Maxn];
    int size[Maxn];
    
    void add(int u, int v, int w) {
    	g[++e] = (edge){v, head[u], w}, head[u] = e;
    }
    
    template <int N> struct SGMTtree {
    	LL tree[N << 3], add[N << 3];
    #define lc(x) ((x) << 1)
    #define rc(x) ((x) << 1 | 1)
    #define ls rt << 1, l, mid
    #define rs rt << 1 | 1, mid + 1, r
    	void pushup(int rt) { tree[rt] = min(tree[lc(rt)], tree[rc(rt)]); }
    	void pushdown(int rt) {
    		if (add[rt]) {
    			LL &v = add[rt];
    			tree[lc(rt)] += v; tree[rc(rt)] += v;
    			add[lc(rt)] += v; add[rc(rt)] += v;
    			v = 0;
    		}
    	}
    	void build(int rt, int l, int r) {
    		if (l == r) {
    			tree[rt] = isleaf[l] ? dis[l] : LLONG_MAX / 2;
    			return ;
    		}
    		int mid = (l + r) >> 1;
    		build(ls), build(rs);
    		pushup(rt);
    	}
    	void modify(int rt, int l, int r, int P, int Q, int v) {
    		if (P <= l && r <= Q) {
    			tree[rt] += v, add[rt] += v;
    			return ;
    		}
    		int mid = (l + r) >> 1; pushdown(rt);
    		if (Q <= mid) modify(ls, P, Q, v);
    		else if (P >= mid + 1) modify(rs, P, Q, v);
    		else modify(ls, P, Q, v), modify(rs, P, Q, v);
    		pushup(rt);	
    	}
    	LL query(int rt, int l, int r, int P, int Q) {
    		if (P <= l && r <= Q) return tree[rt];
    		int mid = (l + r) >> 1; pushdown(rt);
    		if (Q <= mid) return query(ls, P, Q);
    		else if (P >= mid + 1) return query(rs, P, Q);
    		else return min(query(ls, P, Q), query(rs, P, Q));
    	}
    #undef lc
    #undef rc
    #undef ls
    #undef rs
    };
    
    SGMTtree <Maxn> SGT;
    
    void dfsInit(int u, int pa) {
    	isleaf[u] = 1;  size[u] = 1;
    	for (int i = head[u]; ~i; i = g[i].nxt) {
    		int v = g[i].to;
    		if (v != pa) {
    			dis[v] = dis[u] + g[i].w, isleaf[u] = 0;
    			dfsInit(v, u);
    			size[u] += size[v];
    		}
    	}
    }
    
    struct node {
    	int l, r, Id;
    };
    vector <node> qset[Maxn];
    
    void init() {
    	clar(head, -1);
    	n = read(), q = read();
    	rep (i, 2, n) {
    		int pa = read(), w = read();
    		add(pa, i, w), add(i, pa, w);
    	}
    
    	rep (i, 1, q) {
    		int u = read(), l = read(), r = read();
    		qset[u].push_back((node){l, r, i});
    	}
    
    	dfsInit(1, 0);
    	SGT.build(1, 1, n);
    }
    
    void dfsAnswer(int u, int pa) {
    	rep (i, 0, qset[u].size() - 1) {
    		node s = qset[u][i];
    		ans[s.Id] = SGT.query(1, 1, n, s.l, s.r);
    	}
    	for (int i = head[u]; ~i; i = g[i].nxt) {
    		int v = g[i].to;
    		if (v != pa) {
    			SGT.modify(1, 1, n, v, v + size[v] - 1, -g[i].w);
    			if (v != 1) SGT.modify(1, 1, n, 1, v - 1, g[i].w);
    			if (v + size[v] - 1 != n) SGT.modify(1, 1, n, v + size[v], n, g[i].w);
    			dfsAnswer(v, u);
    			SGT.modify(1, 1, n, v, v + size[v] - 1, g[i].w);
    			if (v != 1) SGT.modify(1, 1, n, 1, v - 1, -g[i].w);
    			if (v + size[v] - 1 != n) SGT.modify(1, 1, n, v + size[v], n, -g[i].w);
    		}
    	}
    }
    
    void solve() {
    	dfsAnswer(1, 0);
    	rep (i, 1, q) write(ans[i]), putchar('
    ');
    }
    
    int main() {
        freopen("CF1110F.in", "r", stdin);
        freopen("CF1110F.out", "w", stdout);
    
        init();
        solve();
    
    #ifdef Qrsikno
        debug("
    Running time: %.3lf(s)
    ", clock() * 1.0 / CLOCKS_PER_SEC);
    #endif
        return 0;
    }
    
  • 相关阅读:
    读书笔记--Linux Shell脚本攻略
    深入理解javascript原型链
    javascript基本类型及类型转换
    ECMAScript6 Promise
    git初体验
    走进git
    Dom编程优化
    go 递归实现快排
    go语言排序
    实现一个迭代器类
  • 原文地址:https://www.cnblogs.com/qrsikno/p/10364957.html
Copyright © 2011-2022 走看看