jzoj5394 【NOIP2017提高A组模拟10.5】Ping

来源:互联网 发布:清华软件研究生怎么样 编辑:程序博客网 时间:2024/06/05 22:42

题面

这里写图片描述
这里写图片描述

分析

很容易看出模型:有若干条路径,选最少的点使得每条路径上都有点。并给出方案。
考虑一条链,其实就抽象成数轴上的线段。显然是贪心。(然而我最后五分钟才想起来!?

把线段按右端点从小到大排序,考虑右端点最左的一条线段,其他线段要么与他没有交集,要么从右边有交。那么这条线段取点一定是取右端点能覆盖更多的线段。
把覆盖掉的线段删除,重复上述步骤,直到覆盖完毕。
还能得出一个结论: 只选右端点。

对于树上的两条路径,我们知道路径A交路径B,要么A的lca在B上,要么B的lca在A上。
所以,对于一条Lca深度最大的路径,一定在他这选一个点(没有其他路径的lca在他上面)。 自然是选深度最小的lca最好了,这样能覆盖更多上面的路径。
证明嘛感性一点好了C(・ω・)ノ

所以拿个树剖维护下就好了。

Demo

#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#define lowbit(x) ((x)&-(x))using namespace std;const int N = 1e5 + 10;int n,m,k;int to[N*2],nex[N*2],final[N],tot;int dep[N],fa[N],top[N],size[N],hvy[N],loc[N];int ans[N],t[N];struct path{    int x,y,lca;} s[3*N];bool cmp(path a,path b) {return dep[a.lca]>dep[b.lca];}void link(int x,int y) {    to[++tot]=y,nex[tot]=final[x],final[x]=tot;}void dfs(int x) {    dep[x]=dep[fa[x]]+1;    size[x]=1;    for (int i=final[x]; i; i=nex[i]) {        int y=to[i]; if (y==fa[x]) continue;        fa[y]=x;        dfs(y);        size[x]+=size[y];        if (size[y]>size[hvy[x]]) hvy[x]=y;    }}int stm;void build(int x) {    loc[x]=++stm;    if (!top[x]) top[x]=x;    if (hvy[x]) top[hvy[x]]=top[x],build(hvy[x]);    for (int i=final[x]; i; i=nex[i]) {        if (to[i]!=fa[x] && to[i]!=hvy[x]) build(to[i]);    }}int lca(int x,int y) {    while (top[x]!=top[y]) {        if (dep[top[x]]<dep[top[y]]) swap(x,y);        x=fa[top[x]];    }    return dep[x]>dep[y]?y:x;}void change(int x) {    for (; x<=n; x+=lowbit(x)) t[x]++;}int sum(int x) {    int sum=0;    for (; x; x-=lowbit(x)) sum+=t[x];    return sum;}bool query(int x,int y) {    while (top[x]!=top[y]) {        if (sum(loc[x]) - sum(loc[top[x]]-1) > 0) return 1;        x=fa[top[x]];    }    if (sum(loc[x]) - sum(loc[y]-1) > 0) return 1;    return 0;}int main() {    freopen("ping.in","r",stdin);    //freopen("ping.out","w",stdout);    cin>>n>>m;    for (int i=1; i<=m; i++) {        int u,v; scanf("%d %d",&u,&v);        link(u,v),link(v,u);    }    dfs(1);    build(1);    cin>>k;    for (int i=1; i<=k; i++) {         int x,y; scanf("%d %d",&s[i].x,&s[i].y);         s[i].lca=lca(s[i].x,s[i].y);    }    sort(s+1,s+1+k,cmp);    for (int i=1; i<=k; i++) {        if (query(s[i].x,s[i].lca) + query(s[i].y,s[i].lca) == 0) {            change(loc[s[i].lca]);            ans[++ans[0]]=s[i].lca;        }    }    cout<<ans[0]<<endl;    for (int i=1; i<=ans[0]; i++) printf("%d\n",ans[i]);}