这个题目其实算是贪心吧,感觉自己贪心有点菜,这几天要把贪心练一下了
建树,dfs什么的就不说了,这里主要讲下思路
就是建完树后,给你两个点
然后求出他们的lca,将这两个点u,v和lca,dlca(lca点的深度)存在一个结构体数组中
然后将这个数组按深度从大到小排序
接着遍历这个数组
每次看u,v有没有访问过,如果有就不管,如果没有,就将他们的lca点拿掉并将lca点的所有子节点记为访问过并且ans++
最后输出ans就好了
其实,为什么这样做可以呢
对于一个u,v,我们要做的就是把他们分开,我们就可以拿掉链接u,v上的点的任意一个就好,那么就会出现一个问题
如果有另外两个点的lca正好经过这一条链,那么如果我只拿掉那个点的lca就好了
如果我们这样排序的话,其实就保证了这种情况,也就是保证了最优
还有一点,我们标记已访问过的点时,不需要用到树链剖分,因为是对子树的操作,dfs序就可以了
这个题目有点手残,用的线段树求的lca,代码量直接爆炸了
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 60010
using namespace std;
struct Edge
{
int next,en;
};
struct Save
{
int node,dep;
Save(int n,int d){node=n;dep=d;}
Save(){}
};
bool operator < (Save a,Save b)
{return a.dep<b.dep;}
struct Node
{
int u,v;
Save lca;
};
bool operator < (Node a,Node b)
{return a.lca.dep<b.lca.dep;}
bool cmp(Node a,Node b)
{return a.lca.dep>b.lca.dep;}
Edge edge[maxn];
Node node[maxn];
Save save[maxn*2];
Save segt[maxn<<2];//线段树的大小为节点大小的4倍
int head[maxn],cnte;
int dfsx,in[maxn],out[maxn],vis[maxn],cntn;
int LCAArray[maxn*2];
void init()
{
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
cnte=0;cntn=0;dfsx=0;
}
void addedge(int st,int en)
{
cnte++;
edge[cnte].en=en;
edge[cnte].next=head[st];
head[st]=cnte;
return;
}
void addnode(int u,int v,Save lca)
{
cntn++;
node[cntn].u=u;node[cntn].v=v;
node[cntn].lca=lca;
return;
}
void dfs(int root,int depth)//dfs没问题
{
dfsx++;
in[root]=dfsx;vis[root]=1;
save[dfsx].dep=depth;save[dfsx].node=root;
for (int k=head[root];k!=-1;k=edge[k].next)
if (!vis[edge[k].en])
{
dfs(edge[k].en,depth+1);
dfsx++;
save[dfsx].dep=depth;save[dfsx].node=root;
}
out[root]=dfsx;
return;
}
void build(int root,int beg,int en)//线段树建树函数
{
if (beg==en)
segt[root]=save[beg];
else
{
build(root*2,beg,(beg+en)/2);
build(root*2+1,(beg+en)/2+1,en);
if (segt[root*2]<segt[root*2+1])
segt[root]=segt[root*2];
else segt[root]=segt[root*2+1];
}
return;
}
Save query(int root,int l,int r,int ql,int qr)
{
if(l == ql && r == qr) return segt[root];
int mid=(l+r)/2;
if(qr <= mid) return query(root*2,l,mid,ql,qr);
else if(ql >= mid + 1) return query(root*2+1,mid+1,r,ql,qr);
return min(query(root*2,l,mid,ql,mid), query(root*2+1,mid + 1,r,mid + 1,qr));
}
void initLCA(int n)
{
dfs(0,1);
build(1,1,dfsx);
}
Save LCA(int u,int v)
{
int qbeg,qend;
if (in[u]<in[v])
{qbeg=in[u];qend=in[v];}
else
{qbeg=in[v];qend=in[u];}
return query(1,1,dfsx,qbeg,qend);
}
struct Segt
{
int val,addmark;
};
Segt segtf[maxn<<2];
void pushdown(int root)
{
if (segtf[root].addmark!=0)
{
segtf[root*2].val+=segtf[root].addmark;
segtf[root*2].addmark+=segtf[root].addmark;
segtf[root*2+1].val+=segtf[root].addmark;
segtf[root*2+1].addmark+=segtf[root].addmark;
segtf[root].addmark=0;
}
return;
}
int queryf(int root,int l,int r,int poi)
{
if(l==r) return segtf[root].val;
pushdown(root);
int mid=(l+r)/2;
if(poi <= mid) return queryf(root*2,l,mid,poi);
else if(poi >= mid + 1) return queryf(root*2+1,mid+1,r,poi);
}
void updatef(int root,int rst,int ren,int beg,int en,int val)
{
if (rst>=beg&&ren<=en)
{
segtf[root].val+=val;
segtf[root].addmark+=val;
}
else if (rst>en||ren<beg) {return;}
else
{
pushdown(root);
int mid=(rst+ren)/2;
updatef(root*2,rst,mid,beg,en,val);
updatef(root*2+1,mid+1,ren,beg,en,val);
segtf[root].val=segtf[root*2].val&&segtf[root*2+1].val;
}
}
int main()
{
int n,m;
while(~scanf("%d",&n))
{
init();
for (int k=1;k<=n;k++)
{
int st,en;
scanf("%d %d",&st,&en);
addedge(st,en);addedge(en,st);
}
n++;
initLCA(n);
scanf("%d",&m);
for (int k=1;k<=m;k++)
{
int u,v;
Save lca;
scanf("%d %d",&u,&v);
lca=LCA(u,v);
addnode(u,v,lca);
}
sort(node+1,node+1+cntn,cmp);
memset(segtf,0,sizeof(segtf));
int ans(0);
for (int k=1;k<=cntn;k++)
{
int u,v,l;
u=node[k].u;v=node[k].v;l=node[k].lca.node;
if ((queryf(1,1,dfsx,in[u])==0)&&(queryf(1,1,dfsx,in[v])==0))
{
ans++;
updatef(1,1,dfsx,in[l],out[l],1);
}
}
printf("%d\n",ans);
}
return 0;
}