给出一棵树,给出N条边,问这些边两两之间是否满足两个条件之一①覆盖对方或被对方覆盖 ②没有相交。如果都满足输出Yes,否则输出No。
考场上第一眼就觉得是树剖,毕竟前段时间天天见到这种类型的东西。
做法有点差分的意思,在每条边的两个顶点异或上某个值,然后查询这条边上的异或和,如果合法异或和当然为0。
但这样一来有个问题,就是一条被覆盖的边,其顶点可能与覆盖它的那条边的顶点之一重合,统计的时候就会出问题。考场上想了很久,最后逼不得已在树剖外层写了个特判,结果 0 pts滚粗。
说起来方法其实很简单,只需要把边按长度从小到大排个序再依次加入就完成了~
(至于为什么调试半天只有98pts我也很纳闷,但方法应该没错 )
#include
#define rint register int
#define iint inline int
#define ivoid inline void
#define endll '\n'
#define ll long long
using namespace std;
const int N=1e6+5;
const int M=3e3+5;
const int inf=0x3f3f3f3f;
int m,n,q,k,x,y,z,u,v,w,s,t,l,r,ql,qr,flag;
int a[N],b[N],a1[N],b1[N],head[N],dis[N],vis[N];
int fa[N],deep[N],size[N],son[N],id[N],top[N],ori[N],val[N<<2];
int sum,cnt,ans,res,num,tot;
struct Edge{int v,next;}edge[N<<2];//树上的边
struct Acc{int u,v,len;}acc[N<<2];//要统计的边
iint rad()
{
int x=0,f=1;char c;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
ivoid addedge(int u,int v){edge[++cnt]=(Edge){v,head[u]},head[u]=cnt;}
ivoid dfs1(int x)
{
size[x]=1;
for(rint i=head[x];i;i=edge[i].next){
int d=edge[i].v;
if(d==fa[x])continue;
fa[d]=x,deep[d]=deep[x]+1,dfs1(d);
if(size[d]>size[son[x]])son[x]=d;
size[x]+=size[d];
}
}
ivoid dfs2(int x,int op)
{
id[x]=++tot;
ori[tot]=x;
top[x]=op;
if(!son[x])return;
dfs2(son[x],op);
for(rint i=head[x];i;i=edge[i].next){
int d=edge[i].v;
if(d==son[x]||d==fa[x])continue;
dfs2(d,d);
}
}
ivoid pushup(int n){val[n]=val[n<<1]^val[(n<<1)|1];}
ivoid build(int n,int l,int r)
{
if(l==r){return;}
int mid=(l+r)>>1;
build(n<<1,l,mid);build((n<<1)|1,mid+1,r);
pushup(n);
}
ivoid query(int n,int l,int r,int ql,int qr)
{
if(l>=ql&&r<=qr){ans^=val[n];return;}
int mid=(l+r)>>1;
if(mid>=ql)query(n<<1,l,mid,ql,qr);
if(mid<qr)query((n<<1)|1,mid+1,r,ql,qr);
}
ivoid change_one(int n,int l,int r,int pos,int change)
{
if(l==r){val[n]^=change;return;}
int mid=(l+r)>>1;
if(mid>=pos)change_one(n<<1,l,mid,pos,change);
else change_one((n<<1)|1,mid+1,r,pos,change);
pushup(n);
}
ivoid Lca_query(int x,int y)
{
ans=12321;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
ql=id[top[x]],qr=id[x],query(1,1,n,ql,qr);
x=fa[top[x]];
}
if(deep[x]<deep[y])swap(x,y);
ql=id[y],qr=id[x],query(1,1,n,ql,qr);
if(ans!=12321){cout<<"No";exit(0);}
}
iint Lca(int x,int y)
{
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
x=fa[top[x]];}
if(deep[x]<deep[y])swap(x,y);
return y;
}
iint cmp(Acc q1,Acc q2)
{
return q1.len<q2.len;
}
int main()
{
// freopen("quence.in","r",stdin);
// freopen("quence.out","w",stdout);
n=rad();m=rad();srand(time(0));
int size=40<<20;
__asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//提交用这个
for(rint i=1;i<n;i++)u=rad(),v=rad(),addedge(u,v),addedge(v,u);
dfs1(1);dfs2(1,1);
for(rint i=1;i<=m;i++){
a1[i]=rad();b1[i]=rad();
acc[i]=(Acc){a1[i],b1[i],deep[a1[i]]+deep[b1[i]]-2*deep[Lca(a1[i],b1[i])]};
}
sort(acc+1,acc+m+1,cmp);build(1,1,n);
for(rint i=1;i<=m;i++){
int k=rand();
change_one(1,1,n,id[acc[i].u],k);change_one(1,1,n,id[acc[i].v],k);
Lca_query(acc[i].u,acc[i].v);
}
cout<<"Yes";
exit(0);
}
如果有神仙看出来为什么这份代码到不了满分麻烦告诉我,感激不尽~