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");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章