JZOJ5394. 【NOIP2017提高A组模拟10.5】Ping 树上差分 树状数组

来源:互联网 发布:博罗网络问政 编辑:程序博客网 时间:2024/05/16 15:01

题意:有一棵树,给你一些点对,要求这些点对不能联通,问最少需要拆掉多少个点。输出方案。
比赛的时候有想法的一道题目,但是由于比较煞笔所以只想到了树剖,然后觉得万一不能切就亏大了,求稳所以没打。
考虑一对点,他们的路径为x-lca-y,那么对于这条路径上查询是否有被拆掉的点,没有就直接把lca拆掉。
那么我们对于所有点对都这么干,按照dfs序倒着处理,证明的话,把树看成一个序列,会发现按照右端点排序贪心最优,延伸到树上也是一样的道理。
维护路径点对数量,根据bit前缀和性质,我们可以在区间左边打一个+1,右边打一个-1标记。
注意,如果剖分的话才可以直接对dfn[x],dfn[y]打标记,不然的话就要记录每个点子树的dfn区间,剖分才能把点化成线段(有序),就是pos[dfn[x]],pos[dfn[y]]。
各有千秋吧。

#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=3e5+5;int n,m,k;int a[N];int dfn[N],l[N],r[N],head[N],next[N],go[N];int fa[N][20],dep[N],size[N],pos[N];bool vis[N];int t[N],tot;struct node{    int x,y,lca;}b[N];inline void addedge(int x,int y){    go[++tot]=y;    next[tot]=head[x];    head[x]=tot;}int tim;inline int lowbit(int x){    return x&(-x);}inline void add(int x,int y){    while (x<=n)    {        t[x]+=y;        x+=lowbit(x);    }}inline int ask(int x){    int ret=0;    while (x>0)    {        ret+=t[x];        x-=lowbit(x);    }    return ret;}inline void dfs(int x){    dfn[x]=++tim;    dep[x]=dep[fa[x][0]]+1;    l[x]=tim;    fo(i,1,18)fa[x][i]=fa[fa[x][i-1]][i-1];    for(int i=head[x];i;i=next[i])    {        int v=go[i];        if (v!=fa[x][0])        {            fa[v][0]=x;            dfs(v);        }    }    r[x]=tim;}bool cmp(node x,node y){    return dfn[x.lca]>dfn[y.lca];}inline int lca(int x,int y){    if (dep[x]<dep[y])swap(x,y);    fd(i,18,0)    if (dep[fa[x][i]]>=dep[y])x=fa[x][i];    if (x==y)return x;    fd(i,18,0)    if (fa[x][i]!=fa[y][i])    {        x=fa[x][i];        y=fa[y][i];    }    return fa[x][0];}int main(){    //freopen("ping.in","r",stdin);    //freopen("ping.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,1,m)    {        int x,y;        scanf("%d%d",&x,&y);        addedge(x,y),addedge(y,x);    }    dfs(1);    scanf("%d",&k);    int ans=0,tot=0;    fo(i,1,k)    {        int x,y;        scanf("%d%d",&x,&y);        int Lca=lca(x,y);        b[i].x=x,b[i].y=y,b[i].lca=Lca;    }    sort(b+1,b+1+k,cmp);    fo(i,1,k)    {            int x=b[i].x,y=b[i].y,Lca=b[i].lca;            int tmp1=ask(dfn[x]);            int tmp2=ask(dfn[y]);            int tmp3=ask(dfn[Lca]);            int tmp4=ask(dfn[fa[Lca][0]]);            if(tmp1+tmp2-tmp3-tmp4<=0)            {                ans++,vis[Lca]=1;                add(dfn[Lca],1);                add(r[Lca]+1,-1);            }    }    printf("%d\n",ans);    fo(i,1,n)if (vis[i])printf("%d ",i);    printf("\n");}
阅读全文
0 0
原创粉丝点击