zoukankan      html  css  js  c++  java
  • [HNOI2015]接水果

    题面

    题解

    这道题要求关于第k大的东西,所以可以想到用主席树或整体二分

    我们可以发现,这道题主要的难点就是路径之间的包含关系,那么我们分情况讨论:

    1. LCA不是两个端点

    令这个盘子的两个端点为(a,b)

    如果被一个水果完全覆盖,

    那么,这个水果的两端分别在(a,b)的子树中

    (pos[a])(a)(dfs)序,(end\_pos[a])是子树中最大的(pos),水果两端分别为(c, d)

    [pos[a] leq pos[c] leq end\_pos[a] \ pos[b] leq pos[d] leq end\_pos[b] ]

    2. LCA是其中一个端点

    (a=LCA(a,b))

    那么,一个点还是在(b)的子树内

    另一个点在这条链的子树外

    (a,b)链上的(a)的儿子为(s)

    那么,水果的一个点一定不在(s)的子树内

    即:

    [pos[b] leq pos[c] leq end\_pos[b] \ pos[d] < pos[s] ; || ; end\_pos[s] < pos[d] ]

    我们将盘子的(pos[a],pos[b],end\_pos[a],end\_pos[b])看成两个点

    组成了一个矩形

    所以,一个盘子如果被水果所完全覆盖

    那么,也就是水果组成的点被盘子组成的矩形所包含

    所以整体二分+扫描线求解即可

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define RG register
    #define clear(x, y) memset(x, y, sizeof(x));
    #define for_edge(i, x) for(RG int i = head[x]; i; i = e[i].next)
    #define OPERATOR(Name, key, opt) inline bool operator opt (const Name &a, const Name &b) { return a.key opt b.key; }
    
    inline int read()
    {
    	int data = 0, w = 1; char ch = getchar();
    	while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if(ch == '-') w = -1, ch = getchar();
    	while(ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    const int maxn(50010);
    struct edge { int next, to; } e[maxn << 1];
    int head[maxn], e_num, n, P, Q, fa[20][maxn], dep[maxn], pos[maxn], end_pos[maxn], cnt, q_cnt;
    inline void add_edge(int from, int to) { e[++e_num] = (edge) {head[from], to}; head[from] = e_num; }
    
    struct Matrix { int x1, y1, x2, y2, k; } t[maxn << 2];
    struct Node { int x, y, k, id; } q[maxn], pl[maxn], pr[maxn];
    struct InNode { int l, r, x, val; } L[maxn];
    OPERATOR(Matrix, k, <); OPERATOR(Node, x, <); OPERATOR(InNode, x, <);
    
    void dfs(int x)
    {
    	pos[x] = ++cnt;
    	for(RG int i = 1; i <= 15; i++) fa[i][x] = fa[i - 1][fa[i - 1][x]];
    	for_edge(i, x)
    	{
    		int to = e[i].to; if(to == fa[0][x]) continue;
    		fa[0][to] = x; dep[to] = dep[x] + 1; dfs(to);
    	}
    	end_pos[x] = cnt;
    }
    
    template<int T>
    inline int LCA(int a, int b)
    {
    	if(dep[a] < dep[b]) std::swap(a, b);
    	for(RG int i = 15; ~i; i--)
    		if(dep[fa[i][a]] > dep[b]) a = fa[i][a];
    	if(fa[0][a] == b) return T ? a : b;
    	a = fa[0][a];
    	for(RG int i = 15; ~i; i--)
    		if(fa[i][a] != fa[i][b]) a = fa[i][a], b = fa[i][b];
    	return T ? a : fa[0][a];
    }
    
    int c[maxn], ans[maxn];
    inline void update(int x, int v) { while(x <= n) c[x] += v, x += x & -x; }
    inline int query(int x) { int Ans = 0; while(x) Ans += c[x], x -= x & -x; return Ans; }
    void Div(int l, int r, int ql, int qr)
    {
    	if(ql > qr) return;
    	if(l == r) { for(RG int i = ql; i <= qr; i++) ans[q[i].id] = t[l].k; return; }
    			
    	int mid = (l + r) >> 1, tl = 0, tr = 0, cntL = 0, p = 1;
    	for(RG int i = l; i <= mid; i++)
    		L[++cntL] = (InNode) {t[i].y1, t[i].y2, t[i].x1, 1},
    		L[++cntL] = (InNode) {t[i].y1, t[i].y2, t[i].x2 + 1, -1};
    	std::sort(L + 1, L + cntL + 1);
    
    	for(RG int i = ql; i <= qr; i++)
    	{
    		while(p <= cntL && L[p].x <= q[i].x) update(L[p].l, L[p].val), update(L[p].r + 1, -L[p].val), ++p;
    		int sum = query(q[i].y);
    		if(q[i].k <= sum) pl[++tl] = q[i];
    		else q[i].k -= sum, pr[++tr] = q[i];
    	}
    	
    	for(RG int i = 1; i < p; i++) update(L[i].l, -L[i].val), update(L[i].r + 1, L[i].val);
    	for(RG int i = 1; i <= tl; i++) q[ql + i - 1] = pl[i];
    	for(RG int i = 1; i <= tr; i++) q[ql + tl + i - 1] = pr[i];
    
    	Div(l, mid, ql, ql + tl - 1);
    	Div(mid + 1, r, ql + tl, qr);
    }
    
    int main()
    {
    	n = read(); P = read(); Q = read();
    	for(RG int i = 1, a, b; i < n; i++) a = read(), b = read(), add_edge(a, b), add_edge(b, a);
    	dep[1] = 1; dfs(1);
    	for(RG int i = 1, a, b, k; i <= P; i++)
    	{
    		a = read(); b = read(); k = read();
    		if(pos[a] > pos[b]) std::swap(a, b);
    		int lca = LCA<0>(a, b);
    		if(a != lca) t[++q_cnt] = (Matrix) {pos[a], pos[b], end_pos[a], end_pos[b], k};
    		else
    		{
    			int Lca = LCA<1>(a, b);
    			if(pos[Lca] != 1) t[++q_cnt] = (Matrix) {1, pos[b], pos[Lca] - 1, end_pos[b], k};
    			if(end_pos[Lca] != n) t[++q_cnt] = (Matrix) {pos[b], end_pos[Lca] + 1, end_pos[b], n, k};
    		}
    	}
    
    	for(RG int i = 1, a, b, k; i <= Q; i++)
    	{
    		a = read(); b = read(); k = read();
    		if(pos[a] > pos[b]) std::swap(a, b);
    		q[i] = (Node) {pos[a], pos[b], k, i};
    	}
    
    	std::sort(t + 1, t + q_cnt + 1);
    	std::sort(q + 1, q + Q + 1);
    	clear(c, 0);
    	Div(1, q_cnt, 1, Q);
    
    	for(RG int i = 1; i <= Q; i++) printf("%d
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Mysql性能优化
    PHP IF判断简写
    PHP与MYSQL事务处理
    js获取select标签选中的值
    oralce 的安装以及plsql的配置的html连接
    mysql 中启动服务的命令 、登录命令、退出命令 mysql 的常用命令
    oracle 中 某个字段的长度不够的sql 语句
    随机获得id的方法
    java中解析excel 批量插入数据库
    java 调用存储过程
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/9807442.html
Copyright © 2011-2022 走看看