树链剖分 树
来源:互联网 发布:淘宝情侣装店铺排名 编辑:程序博客网 时间: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"); }}
阅读全文
0 0
- 树链剖分 树
- ”树链剖分+线段树“详解
- POJ3237 树链剖分+线段树
- bzoj2836: 魔法树 树链剖分
- BZOJ3924【树链剖分】【线段树】
- BZOJ4034【树链剖分】【线段树】
- 【bzoj2836】【魔法树】【树链剖分】
- BZOJ 3306|树|树链剖分
- 3306: 树|树链剖分
- poj3237Tree 【树链剖分+线段树】
- bzoj2588 -- 树链剖分+主席树
- 树链剖分 BZOJ3589 动态树
- 树链剖分+线段树
- SPOJ 375 (树链剖分+线段树)
- SPOJ 375 (树链剖分+线段树)
- hdu 3966 (树链剖分+线段树)
- poj 3237(树链剖分+线段树)
- hdu 3804(树链剖分+线段树)
- PTA 7-9 目录树
- javascript滚动条事件动态悬浮页面对象
- 基于ionic+cordova+angularJs从零开始搭建自己的移动端H5 APP
- 第八周项目4-稀疏矩阵的三元组表示的实现及应用
- Dgital Image Processing hm2
- 树链剖分 树
- 【机器学习】强化学习总结
- Dubbo扩展:Dubbox
- 模拟IIC通信
- Vue-router 切换组件页面时进入进出动画
- 九度oj 1005 Graduate Admission
- LaTex(PART XV)figure
- 古文觀止卷九_賀進士王參元失火書_柳宗元
- 如何整理知识体系