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");
}