树链剖分 树

来源:互联网 发布:淘宝情侣装店铺排名 编辑:程序博客网 时间:2024/06/01 20:00

这里写图片描述
很明显一点,T1树里每一条边都会被选取一次。把T2树的每一条边看成一个线段覆盖。每次找到一个只被覆盖了一次的线段,找到他是被那个区间覆盖的,把那个区间删去。如果最后能删完,就有解,删不完就是无解。
搞个树剖维护区间被覆盖的最小次数。但是较难的地方是:如何判断某一条边是被那个区间覆盖的。其实我们可以再维护一个值,把覆盖这个点的区间的编号加起来,因为我们找线段时只是找被覆盖一次的线段,所以一定就是他的编号了。因此在删区间的时候,额外维护这个变量。
另一个比较难的地方:找到你要删的那条边后,把它赋成inf,他就不会对答案产生影响了(维护的是区间最小值,0可是比1小的。。),我曾经卡在一个地方,就是在删区间时删出来一个0怎么办。那么这个0一定不会再被那一个区间选择了。但是很明显每条边都是要被选的,那这就一定无解了。
注:把边权下放到点时注意把用不到的点赋成无限大。

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#define N 200005#define inf 1000000000#define mem(x) (memset(x,0,sizeof(x)))#define ll long longusing namespace std;struct road{int v,next;}lu[N*2];struct node{int x,y;}a[N];int T,ans,n,e,cnt,adj[N],f[N],top[N],sz[N],son[N],id[N],dep[N];void add(int u,int v){lu[++e]=(road){v,adj[u]};adj[u]=e;}namespace TREE{    struct tree{int l,r,su,lsu;ll h,lh;}t[N*4];    inline void build(int l,int r,int x)    {        t[x].l=l;t[x].r=r;        t[x].h=t[x].lh=t[x].lsu=t[x].su=0;        if(l==r)return;        int mid=l+r>>1;        build(l,mid,x*2);        build(mid+1,r,x*2+1);    }    inline void down(int x)    {        int h=t[x].lh,su=t[x].lsu;        t[x].lh=t[x].lsu=0;        t[x*2].h+=h;t[x*2].lh+=h;        t[x*2+1].h+=h;t[x*2+1].lh+=h;        t[x*2].su+=su;t[x*2].lsu+=su;        t[x*2+1].su+=su;t[x*2+1].lsu+=su;    }    inline void Q(int x)    {        if(t[x].l==t[x].r){ans=t[x].h,t[x].su=inf;return;}        if(t[x].lh)down(x);        if(t[x*2].su==1)Q(x*2);        else Q(x*2+1);        t[x].su=min(t[x*2].su,t[x*2+1].su);    }    inline void add(int l,int r,int k,ll h,int x)    {        if(t[x].l>=l&&t[x].r<=r)        {            t[x].su+=k;t[x].lsu+=k;            t[x].h+=h;t[x].lh+=h;            if(l==1)t[x].su=inf;            return;        }        if(t[x].lh)down(x);        int mid=t[x].l+t[x].r>>1;        if(l<=mid)add(l,r,k,h,x*2);        if(r>mid)add(l,r,k,h,x*2+1);        t[x].su=min(t[x*2].su,t[x*2+1].su);    }    inline void C(int x,int y,int k,ll h)    {        int fx=top[x],fy=top[y];        while(fx^fy)        {            if(dep[fx]<dep[fy])swap(fx,fy),swap(x,y);            add(id[fx],id[x],k,h,1);            x=f[fx],fx=top[x];        }        if(x==y)return;        if(id[x]>id[y])swap(x,y);        add(id[x]+1,id[y],k,h,1);    }}using namespace TREE;inline void dfs1(int x,int fa){    f[x]=fa;sz[x]=1;dep[x]=dep[fa]+1;    for(int i=adj[x];i;i=lu[i].next)    {        int to=lu[i].v;if(to==fa)continue;        dfs1(to,x);sz[x]+=sz[to];        if(sz[to]>sz[son[x]])son[x]=to;    }}inline void dfs2(int x,int y){    top[x]=y;id[x]=++cnt;    if(!son[x])return;    dfs2(son[x],y);    for(int i=adj[x];i;i=lu[i].next)    {        int to=lu[i].v;        if(to==f[x]||to==son[x])continue;        dfs2(to,to);    }}bool check(){    dfs1(1,0);dfs2(1,1);build(1,n,1);add(1,1,1,inf,1);    for(int i=1;i<n;i++)C(a[i].x,a[i].y,1,i);    for(int i=1;i<n;i++)    {        if(t[1].su!=1)return 0;        ans=0;Q(1);        C(a[ans].x,a[ans].y,-1,-ans);    }    return 1;}int main(){    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);e=cnt=0;        mem(sz);mem(son);mem(f);mem(top);mem(adj);mem(dep);mem(id);        for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);        for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),a[i]=(node){x,y};        if(check())printf("YES\n");        else printf("NO\n");    }}
原创粉丝点击