问题 I: Monitoring Ski Paths 树链剖分+LCA+树状数组+贪心

问题 I: Monitoring Ski Paths

时间限制: 1 Sec  内存限制: 128 MB
[提交] [状态] [命题人:admin]

题目描述

Fresh powder on a sunny day: it is a great time to ski! Hardcore skiers flock to a large mountain in the Rockies to enjoy these perfect conditions. The only way up the mountain is by helicopter; skiers jump out and ski down the mountain.

This process sounds a bit chaotic, so some regulations are in place. Skiers can only enter or exit the mountain at a set of designated locations called junctions. Once on the mountain, they are only allowed to travel along designated ski paths, each of which starts at one junction and ends at another junction lower on the mountain. Multiple ski paths might start at the same junction, but no two ski paths end at the same junction to avoid collisions between skiers.

Finally, each skier must register a ski plan a day in advance with the helicopter service. The ski plan specifies the junction they fly up to and the junction lower on the mountain where they get picked up. If a skier shows up to the mountain, they must follow their plan; but some skiers get sick and do not show up at all.

Your job is to look through the ski plans and set up monitors at some of the junctions to count how many skiers actually show up. To keep operating costs as low as possible, you should determine the minimum number of junctions that need to be monitored so that each skier passes through at least one monitored junction.

Figure 1: Illustration of the first sample input.
Figure 1 shows the first sample input. The dashed lines indicate the five different plans that were registered by skiers. By monitoring junctions 5, 9, and 10, you can ensure that all plans include at least one monitored junction. Monitoring fewer functions would miss some skiers.

 

输入

The first line of input has three integers n, k, and m, where n (2≤n≤250000) is the number of junctions, k (1≤k<n) is the number of ski paths, and m (1≤m≤250000) is the number of routes.

Then k lines follow, each containing two integers 1≤u,v≤n indicating that there is a ski path that starts at junction u and ends at junction v. No (u,v) pair appears more than once.

Then m lines follow, each containing two distinct integers 1≤s,t≤n. Each line indicates that a skier plans to land at junction s and ski down the mountain to junction t. It is guaranteed it is possible to reach junction t from junction s by following ski paths and that junction t is at the base of the mountain (i.e. no ski paths start at t). No (s,t) pair appears more than once.

 

输出

Output the minimum number of junctions that need to be monitored so each ski plan includes at least one monitored junction.

 

样例输入

复制样例数据

10 8 5
1 5
5 6
5 4
7 3
3 10
3 9
10 2
10 8
1 6
5 4
7 2
3 9
10 8

样例输出

3

题解:这个题和  HDU6203 几乎一样,唯一不同的就是,这个不一定是连通图,那么就并查集把他们都连起来算就好了

HDU6203:https://blog.csdn.net/mmk27_word/article/details/95198205

#include <bits/stdc++.h>
using namespace std;
const int N =  250000 + 10;
struct Edge {
    int to, nex;
}e[N * 2];
int n, p, m ;
int head[N], len;
int deep[N];
int in[N], out[N], cnt;
int sum[N];
int num[N], son[N], top[N], f[N];
int ff[N];
void Init() {
    for(int i = 0; i <= n; i++) {
        head[i] = -1;
        deep[i] = -1;
        num[i] = 0;
        son[i] = -1;
        top[i] = -1;
        f[i] = -1;
        sum[i] = 0;
        ff[i] = i;
    }
    sum[n + 1] = 0;
    len = 0;
    cnt = 0;
}
void Addedge(int x, int y) {
    e[len].to = y;
    e[len].nex = head[x];
    head[x] = len++;
}
void dfs1(int u, int fa) {
    f[u] = fa;
    int to;
    num[u] = 1;
    for(int i = head[u]; i != -1; i = e[i].nex) {
        to = e[i].to;
        if(to == fa) continue;
        deep[to] = deep[u] + 1;
         
        dfs1(to, u);
        num[u] += num[to];
        if(son[u] == -1 || num[to] > num[son[u]])
            son[u] = to;
    }
}
void dfs2(int u, int rt, int f) {
    top[u] = rt;
    in[u] = ++cnt; 
    if(son[u] != -1) {
        dfs2(son[u], rt, u);
    }
    int to;
    for(int i = head[u]; i != -1; i = e[i].nex) {
        to = e[i].to;
        if(to == f || to == son[u]) continue;
        dfs2(to, to, u);
    }
     
}
struct Node {
    int x, y, lca;
}b[N ];
int getlca(int x, int y) {
    int fx = top[x], fy = top[y];
    while(fx != fy) {
        if(deep[fx] < deep[fy]) {
            swap(fx, fy);
            swap(x, y);
        }
        x = f[fx];
        fx = top[x];
    }
    if(deep[x] < deep[y]) swap(x, y);
  
    return y; 
}
  
bool cmp(Node x, Node y) {
    return deep[x.lca] > deep[y.lca];
}
  
int lowbit(int x) {
    return x & (- x); 
}
void AddPoint(int x) {
    while(x <= n + 1) {
        sum[x]++;
        x +=lowbit(x);
         
    }
    return ;
} 
int query(int x) {
//  if(x == 0) return 0;
    int res = 0;
    while(x) {
    //  cout<<x<<endl;
        res += sum[x];
        x -= lowbit(x);
    }
    return res;
}
int judge(int x, int y) {
    int fx = top[x], fy = top[y];
    while(fx != fy) {
        if(deep[fx] < deep[fy]) {
            swap(fx, fy);
            swap(x, y);
        }
        if(query(in[x]) - query(in[fx] - 1) != 0) return true;
        x = f[fx];
        fx = top[x];
    }
    if(deep[x] < deep[y]) swap(x, y);
    if(query(in[x]) - query(in[y] - 1) != 0) return true;
    return false; 
}
int fath(int x) {
    return x == ff[x] ? ff[x] : ff[x] = fath(ff[x]);
}
int main() {
    int x, y, z;
    int ans, cnt;
    int xx, yy;
    while(~scanf("%d %d %d", &n, &m, &p)) {
        Init();
        for(int i = 1; i <= m; i++) {
            scanf("%d %d", &x, &y);
            xx = fath(x); yy = fath(y);
            ff[yy] = xx;
            Addedge(x, y);
            Addedge(y, x);
        }
        x = fath(1);
        for(int i = 2; i <= n; i++) {
            y = fath(i);
            if(x == y) continue;
        //  cout << x <<" * " << y << endl;
            ff[y] = x;
            Addedge(x, y);
            Addedge(y, x);
        }
    //  cout <<"WJY" << endl;
        deep[x] = 1;
        dfs1(x, -1);
    //  cout <<"ZX" << endl;
        dfs2(x, x, -1);
    //  cout << "xjl" << endl;
 
        for(int i = 1; i <= p; i++) {
            scanf("%d %d", &x, &y);
            z = getlca(x, y);
            b[i].x = x;
            b[i].y = y;
            b[i].lca = z;
        //  cout<<z<<endl;
        //  cout << in[x] << " " << in[y] << endl;
        }
        sort(b + 1, b + 1 + p, cmp);
        ans = 0;
        for(int i = 1; i <= p; i++ ) {
            if(!judge(b[i].x, b[i].y) ) {
                ans++;
                AddPoint(in[b[i].lca]);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值