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