2017博普杯 东北大学邀请赛(B. Drink too much water)(贪心+树链剖分)

题目地址:https://oj.neu.edu.cn/problem/1204

题目大意:

其实就是树上的线段覆盖,

给出一棵n个结点的树,然后给出树上的一些路径进行覆盖,然后要求选取最少的点,能够把这些线段都占有

(或者说:一开始树上每个结点权值都为0,选取最少的点,把它们的权重变成1,使得询问的每一条路径上有含有权值为1的结点)

题解:

类似线段覆盖(线段覆盖是按照右端点贪心)

这个题就是按照每个路径的lca的深度贪心

也就是说把询问按照lca的深度从大到小排序

然后依次枚举询问

如果当前询问的路径没有权值为1的结点,就把lca赋值成1,答案加1

如果有就跳过

最后输出就可以了

整个过程用树链剖分就可以维护

(第一次wa是没有多组输入输出,第二次wa是把return 0 放在多组数据里了,第三次wa是忘记删freopen。。。orz)

#include <algorithm>
#include <cstring>
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 1e5 + 100;
const int maxm = 5e5 + 100;
int tree[maxn*4], deep[maxn], p[maxn], sz[maxn], son[maxn], top[maxn], F[maxn];
int tot = 0;
vector<int> G[maxn];
struct Que{
    int x, y, lca;
    bool operator <(const Que& B) const{
        return deep[lca] < deep[B.lca];
    }
};
vector<Que> Q;
void Insert(int o, int l, int r, int k, int v){
    if(l == r) { tree[o] = v; return; }
    int mid = (l+r)>>1;
    if(k <= mid) Insert(o*2, l, mid, k, v);
    else Insert(o*2+1, mid+1, r, k, v);
    tree[o] = max(tree[o*2], tree[o*2+1]);
}
int Query(int o, int l, int r, int L, int R){
    if(L <= l && r <= R) return tree[o];
    int mid = (l+r)>>1, ans = 0;
    if(L <= mid) ans = max(ans, Query(o*2, l, mid, L, R));
    if(R > mid) ans = max(ans, Query(o*2+1, mid+1, r, L, R));
    return ans;
}

int dfs1(int x, int fa, int d){
    deep[x] = d;
    p[x] = fa;
    sz[x] = 1;
    for(auto to : G[x]){
        if(fa == to) continue;
        sz[x] += dfs1(to, x, d+1);
        if(sz[to] > sz[son[x]]) son[x] = to;
    }
    return sz[x];
}
void dfs2(int x, int fa){
    F[x] = ++tot;
    if(son[fa] == x) top[x] = top[fa];
    else top[x] = x;
    if(son[x]) dfs2(son[x], x);
    for(auto to : G[x]){
        if(to == fa || to == son[x]) continue;
        dfs2(to, x);
    }
}
int TQuery(int x, int y, int &lca){
    int ans = 0;
    while(top[x] != top[y]){
        if(deep[top[y]] > deep[top[x]]) swap(x, y);
        ans = max(ans, Query(1, 1, tot, F[top[x]], F[x]));
        x = p[top[x]];
    }
    if(deep[x] > deep[y]) swap(x, y);
    ans = max(ans, Query(1, 1, tot, F[x], F[y]));
    lca = x;
    return ans;
}

int main()
{

    int n, m, x, y;
    while(cin>>n){
        tot = 0;
        for(int i = 0; i <= n; i++) G[i].clear();
        memset(son, 0, sizeof(son));
        memset(tree, 0, sizeof(tree));
        for(int i = 1; i <= n; i++){
            scanf("%d %d", &x, &y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        dfs1(0, 0, 1);
        dfs2(0, 0);
        cin>>m;
        Q.resize(m);
        for(int i = 0; i < m; i++){
            scanf("%d %d", &Q[i].x, &Q[i].y);
            TQuery(Q[i].x, Q[i].y, Q[i].lca);
        }
        sort(Q.begin(), Q.end());
        reverse(Q.begin(), Q.end());
        int ans = 0;
        for(auto a : Q){
            int k = TQuery(a.x, a.y, a.lca);
            if(k) continue;
            else Insert(1, 1, tot, F[a.lca], 1), ans++;
        }
        cout<<ans<<endl;
    }
    return 0;
}
时间: 2024-10-08 22:06:48

2017博普杯 东北大学邀请赛(B. Drink too much water)(贪心+树链剖分)的相关文章

记2014英特尔杯嵌入式邀请赛

2014年Intel杯大学生电子设计竞赛嵌入式邀请赛已经圆满结束了,我很高兴能够捧得最高奖Intel杯.自从捧杯的这几天来,各路媒体的采访,学校的祝贺,同学好友的祝贺应接不暇,对此我也表示非常感谢.作为一名大学生,我很明白这个“光环”所带来的也就是这几天的关注而已,而最终也将被请下神坛,继续做我的一位平凡大学生.收获也不能说没有,但收获并不是别人给的,是需要自己去寻找,自己去总结的. 回想六个月的项目经历,可以说是曲折坎坷,又有点神奇美妙,仿佛上帝安排.项目的第一阶段是构思创意,真正的想创意时间

2017 百度杯丶二月场第一周WP

1.祸起北荒 题目: 亿万年前 天子之子华夜,被父神之神末渊上神告知六荒十海之北荒西二旗即将发生一场"百度杯"的诸神之战 他作为天族的太子必须参与到此次诸神之战定六荒十海 华夜临危受命,马上带着火凤凰飞行到北荒"西二旗" 却没想到这六荒之首北荒西二旗果然名不虚传,这是一个位于六层虚数空间上的时空大陆 他需要闯过每一层虚数空间,方能到达虚数空间 第一层虚数空间是需要与一个上古神器"i春秋"进行智能比拼,获取开启第一层虚数空间的flag 启动法诀:

记2017问鼎杯预赛的wp---来自一个小菜鸡的感想

这次准备写一下几个misc和密码题目..很坑. 打了一整天的比赛,越来越觉得自己很菜了. 有一道题目叫做"真真假假",这道题目只有一个提示--Xor.第一眼知道是异或,也就知道这一个信息.打开这个文件发现一堆16进制的有对称美的代码. 1307 0a44 2305 0605 3d01 3e4f 192e 010a4423 1343 1f3c 0a79 011a 310a 0344 2a140e04 211c 3516 5526 0101 0b39 1b00 0e275579 4d3c

2017 ACM/ICPC 广西邀请赛 题解

题目链接  Problems HDOJ上的题目顺序可能和现场比赛的题目顺序不一样, 我这里的是按照HDOJ的题目顺序来写的. Problem 1001 签到 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) typedef long long LL; LL n, f[31]; int ans; int main(){ f[1] = 1LL; fo

2017蓝桥杯第十题(k倍区间)

1 #include<iostream> 2 #include<stdio.h> 3 using namespace std; 4 const int N = 10010; 5 int n,c[N*3],a[N]; 6 int lowbit(int n){ 7 return n&(-n); 8 } 9 void change(int k,int pos){ 10 while(pos<=n){ 11 c[pos]+=k; 12 pos+=lowbit(pos); 13

有趣的两道数论题——2017华杯初赛小高组

首发于订阅号 嗨编程,这是一个以嗨为目标的编程订阅号(仅仅是目标而已),扫码可关注,争取每周5更. 5.从1-20这20个整数中任意取11个数,其中必有两个数的和等于() A. 19    B.20    C.21    D.22 答案:C 解析: 最小的11个数是1~11,当中最大的两个数之和是21,最大的11个数是10~20,当中最小的两个数之和是21,即可确定答案. 9.在一个自然数的所有因数中,能被3整除的因数比奇因数多5个,那么这个自然数最小是_____ 答案:72 解析:考虑对这个自

2017 百度杯丶春秋欢乐赛 writeup

1. 内涵图(Misc) 题目: 我不是一个简单的图片 我是一个有内涵的图片 解:保存到桌面,右键属性->详细信息,即可获得flag. 2. 小电影(Misc) 题目: 我说过 这次比赛是让大家开开心心的度过的 所以 送给你们一个小电影 解:图片被损坏. (1)检查文件头,发现没有GIF8,用winhex补上. (2)重新打开gif,图片已修复. (3)使用Stegsolve分帧查看,可得flag. 3.水果宴 题目: 你吃了多少水果 访问地址:http://120.132.85.112:200

蓝桥杯_基础训练_完美的代价(贪心)

基础练习 完美的代价 时间限制:1.0s   内存限制:512.0MB 问题描述 回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的.小龙龙认为回文串才是完美的.现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串. 交换的定义是:交换两个相邻的字符 例如mamad 第一次交换 ad : mamda 第二次交换 md : madma 第三次交换 ma : madam (回文!完美!) 输入格式 第一行是一个整数N,表示接下来的字符串的长度(N <= 80

2017多校第8场 HDU 6133 Army Formations 线段树合并

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6133 题意:给你一棵n个节点的二叉树,每个节点有一个提交任务的时间,每个节点总的提交任务的罚时为:提交这个节点和其子树所有的任务,每个任务提交时间的总和为该点的罚时.求每个节点提交完所有任务的最小罚时. 解法:根据题意,我们可以知道每个节点的提交的最小罚时为,按照任务的提交时间从小到大的来提交任务,可以得到最小的罚时.所以我们可以用线段树合并,先建立权值线段树,记录权值区间L到R的所有权值sum与s