jzoj5394 ping

Description

这里写图片描述

样例和输入输出懒得弄出来了
最近在补以前没有改完的题目
也恰好在学树剖
发现这道题正好就是一道树剖题
美滋滋

Solution

首先,我们发现这道题目和经典模型线段覆盖有一些相似
回忆一下
对于线段覆盖我们是怎么做的?
按右端点排序后贪心
对于这道题目
我们树剖之后倒dfs序处理
如果有以它为lca且未被破坏的路径
则选择破坏它
这个贪心的正确性?
考虑把每条路径的后序遍历做出来
再按照最后一个点(也就是lca)排序
那么就会得到一个集合{A1,A2,A3……An}
我们必须在A1中选择一个点 并且尽量使得它在A2中包含
那就选lca咯
代码写的比较丑
常数很大
跑了800ms+

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define L rt<<1
#define R (rt<<1)|1
using namespace std;
const int N=100005;
struct edge{
  int x,y,z;    
} a[N*3];
int nx[N<<1],next[N<<1],b[N<<1],c[N<<1],he[N],head[N],fa[N],h[N],seq[N];
int anc[N][18],x,y,ans,i,j,xx,yy,tr[N<<2],w[N],tot,s[N],son[N],top[N];
int num,dfn[N],n,m;
int read(){
    int sum=0;
    char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9'){
        sum=sum*10+c-'0';
        c=getchar();}
    return sum;
}
inline void add(int x,int y){
    nx[++tot]=he[x];he[x]=tot;b[tot]=y;
}
inline void ad(int x,int y){
    next[++tot]=head[x];head[x]=tot;c[tot]=y;
}
void dfs(int x){
    int i,j;
    s[x]=1;
    anc[x][0]=fa[x];
    fo(i,1,17) anc[x][i]=anc[anc[x][i-1]][i-1];
    for(i=he[x];i;i=nx[i]){
        j=b[i];
        if (j==fa[x]) continue;
        fa[j]=x; h[j]=h[x]+1;
        dfs(j);
        s[x]+=s[j];
        if (s[son[x]]<s[j]) son[x]=j;
        }
}
void dfs1(int x,int y){
    int i,j;
    top[seq[dfn[x]=++num]=x]=y;
    if (!son[x]) return;
    dfs1(son[x],top[x]);
    for(i=he[x];i;i=nx[i]){
        j=b[i];
        if (j==fa[x]) continue;
        if (j!=son[x]) dfs1(j,j);}
}
inline void update(int rt){
    tr[rt]=tr[L]+tr[R];
}
void build(int rt,int l,int r){
    if (l==r){
        tr[rt]=1;
        return;}
    int mid=(l+r)>>1;
    build(L,l,mid),build(R,mid+1,r);
    update(rt);
}
int lca(int x,int y){
    int i;
    if (h[x]<h[y]) x^=y,y^=x,x^=y;
    fd(i,17,0) if (h[anc[x][i]]>=h[y]) x=anc[x][i];
    if (x==y) return x;
    fd(i,17,0) if (anc[x][i]^anc[y][i]) x=anc[x][i],y=anc[y][i];
    return anc[x][0];
}
int query(int rt,int l,int r,int x,int y){
    if (l==r&&x==y) return tr[rt];
    int mid=(l+r)>>1;
    if (y<=mid) return query(L,l,mid,x,y);
      else if (x>mid) return query(R,mid+1,r,x,y);
        else return query(L,l,mid,x,mid)+query(R,mid+1,r,mid+1,y);
}
int find(int y,int x){
    for(;top[x]!=top[y];x=fa[top[x]]) {
        int k=query(1,1,n,dfn[top[x]],dfn[x]);
        if (k!=dfn[x]-dfn[top[x]]+1) return 0;
    }
    int k=query(1,1,n,dfn[y],dfn[x]);
    if (k!=dfn[x]-dfn[y]+1) return 0; else return 1;
    return 1;
}
void change(int rt,int l,int r,int x){
    if (l==r) {
        tr[rt]=0; return;
    }
    int mid=(l+r)>>1;
    if (x<=mid) change(L,l,mid,x); else change(R,mid+1,r,x);
    update(rt);
}
int main(){
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    n=read(),m=read();
    fo(i,1,n-1){
        x=read(),y=read();
        add(x,y); add(y,x);}
    fa[1]=1;
    dfs(1);
    dfs1(1,1);
    build(1,1,n);
    m=read();
    tot=0;
    fo(i,1,m){
        a[i].x=read(),a[i].y=read();
        a[i].z=lca(a[i].x,a[i].y);
        ad(a[i].z,i);}
    fd(i,n,1){
        x=seq[i];
        for(j=head[x];j;j=next[j]){
            xx=a[c[j]].x,yy=a[c[j]].y;
            if (find(x,xx)&&find(x,yy)) {
                w[++ans]=seq[i];
                change(1,1,n,i);
                break;}
        }
    }
    printf("%d\n",ans);
    fo(i,1,ans) printf("%d ",w[i]);
    printf("\n");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章