首先隔断一条树边,不计附加边这个树肯定是断成两块了,然后就看附加边有没有连着的两个点在不同的块内。

方法1:BIT乱搞(个人思路)

假设考虑到$x$节点隔断和他父亲的边,要看$x$子树内有没有点连着附加边到子树外的。如果没有,则随便割,有1个,有唯一割法,否则没有。这个可以用dfs序处理好序列后,直接将与一个点附加边牵连的另一个点在BIT里+1,类似晋升者计数那题一样的思路用BIT求答案。$O(mlogn)$。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. #define dbg(x) cerr << #x << " = " << x <<endl
  7. using namespace std;
  8. typedef long long ll;
  9. typedef double db;
  10. typedef pair<int,int> pii;
  11. template<typename T>inline T _min(T A,T B){return A<B?A:B;}
  12. template<typename T>inline T _max(T A,T B){return A>B?A:B;}
  13. template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
  14. template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
  15. template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
  16. template<typename T>inline T read(T&x){
  17. x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
  18. while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
  19. }
  20. const int N=1e5+;
  21. struct thxorz{int to,nxt;}G[N<<],G2[N<<];
  22. int Head[N],Head2[N],tot,tot2;
  23. int n,m,ans;
  24. inline void Addedge(int x,int y){
  25. G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot;
  26. G[++tot].to=x,G[tot].nxt=Head[y],Head[y]=tot;
  27. }
  28. inline void Addedge2(int x,int y){
  29. G2[++tot2].to=y,G2[tot2].nxt=Head2[x],Head2[x]=tot2;
  30. G2[++tot2].to=x,G2[tot2].nxt=Head2[y],Head2[y]=tot2;
  31. }
  32. #define lowbit(x) x&(-x)
  33. int C[N];
  34. inline void Add(int x){for(;x<=n;x+=lowbit(x))++C[x];}
  35. inline int Sum(int x){int ret=;for(;x;x-=lowbit(x))ret+=C[x];return ret;}
  36. int st[N],ed[N],tim;
  37. #define y G[j].to
  38. void dfs(int x,int fa){
  39. st[x]=++tim;
  40. for(register int j=Head[x];j;j=G[j].nxt)if(y^fa)dfs(y,x);
  41. ed[x]=tim;
  42. }
  43. void calc(int x,int fa){
  44. for(register int j=Head[x];j;j=G[j].nxt)if(y^fa){
  45. int tmp=Sum(n)-(Sum(ed[y])-Sum(st[y]-));
  46. calc(y,x);
  47. tmp=Sum(n)-(Sum(ed[y])-Sum(st[y]-))-tmp;
  48. ans+=tmp?tmp==:m;
  49. }
  50. for(register int j=Head2[x];j;j=G2[j].nxt)Add(st[G2[j].to]);
  51. }
  52. #undef y
  53. int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
  54. read(n),read(m);
  55. for(register int i=,x,y;i<n;++i)read(x),read(y),Addedge(x,y);
  56. for(register int i=,x,y;i<=m;++i)read(x),read(y),Addedge2(x,y);
  57. dfs(,);calc(,);
  58. return printf("%d\n",ans),;
  59. }

方法2:树上差分(思路纠正)

当割掉的树边两端有点通过附加边牵连时,附加边对应的两个点形成的链经过这个割边,很容易想。

那么反过来说,每对附加边的点对$x,y$这条链上的边都加上1,相当于这个割边两端的牵连点的对数。

于是这个是树上差分裸题。改链求边。

以前学的树上差分姿势不对,今天重学了一遍。。然后发现网上到处都说这种链差分只要$d_x++,d_y++,d_{lca(x,y)}-=2$,基本没有人说这是为什么。

我自己看了好久没看懂为什么这么做是对的,一气之下自己试着将差分原理搬到树上得知了正确性。你们好多人根本没有懂树上差分的精髓!!

抱歉,上面那句有点狂了,但确实,很多人都没想过树上差分数组$d_i$表示什么?操作为什么是对的?换一种形式还可以改造吗?

差分数组里,$d_i=A_i-A_{i-1}$,而$\sum\limits_{j=1}^{i}d_j=A_i$,类似的,设在树上,若$A_x$是节点$x$与父亲的连边,则$d_x=A_x-\sum\limits_{y\in son}A_y$,这样,$\sum\limits_{y\in 子树x}d_y=A_x$,也就是说,把子树内所有点的$d$加起来就是这个边的值。

于是,修改一条链,拆成修改$x\to lca$和$lca\to y$,$x$到$lca$这个链统一加上一个值,中间的$d_i$差值不变,而$d_x$要加上这个值,$d_{lca}$相应减去这个值,为什么这样,应该就不难理解了,保证了差值的正确性,使得子树和可以正确表示。

这样,如果树边有初始值,也可以通过做差的形式直接构造出这个树上差分数组。

然后再来看题,这里是相当于所有修改操作都做完了,最后统一询问。如果强制在线,应当还是要dfs序做完之后用数据结构维护子树的差分数组之和。但这题可以离线,加上tarjanLCA于是O(n)解决。

另外,同样,点差分也可以通过类似的思路来维护,只是将$lca$稍作修改即可($d_{lca}-=val,d_{fa_{lca}}-=val$)。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. #define dbg(x) cerr << #x << " = " << x <<endl
  7. using namespace std;
  8. typedef long long ll;
  9. typedef double db;
  10. typedef pair<int,int> pii;
  11. template<typename T>inline T _min(T A,T B){return A<B?A:B;}
  12. template<typename T>inline T _max(T A,T B){return A>B?A:B;}
  13. template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
  14. template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
  15. template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
  16. template<typename T>inline T read(T&x){
  17. x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
  18. while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
  19. }
  20. const int N=1e5+;
  21. struct thxorz{int to,nxt;}G[N<<],Q[N<<];
  22. int Head[N],qh[N],tot,qtot;
  23. inline void Addedge(int x,int y){
  24. G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot;
  25. G[++tot].to=x,G[tot].nxt=Head[y],Head[y]=tot;
  26. }
  27. inline void Addquery(int x,int y){
  28. Q[++qtot].to=y,Q[qtot].nxt=qh[x],qh[x]=qtot;
  29. if(x^y)Q[++qtot].to=x,Q[qtot].nxt=qh[y],qh[y]=qtot;
  30. }
  31. int anc[N],vis[N],d[N];
  32. int n,m,ans;
  33. int ancestor(int x){return anc[x]==x?x:anc[x]=ancestor(anc[x]);}
  34. #define y G[j].to
  35. #define qy Q[j].to
  36. void tarjan(int x,int fa){
  37. anc[x]=x;
  38. for(register int j=Head[x];j;j=G[j].nxt)if(y^fa)tarjan(y,x),anc[y]=x;
  39. vis[x]=;
  40. for(register int j=qh[x];j;j=Q[j].nxt)if(vis[qy])d[ancestor(qy)]-=;
  41. }
  42. int dfs(int x,int fa){
  43. int tmp=d[x];
  44. for(register int j=Head[x];j;j=G[j].nxt)if(y^fa)tmp+=dfs(y,x);
  45. if(x^)ans+=tmp?tmp==:m;
  46. return tmp;
  47. }
  48. #undef qy
  49. #undef y
  50. int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
  51. read(n),read(m);
  52. for(register int i=,x,y;i<n;++i)read(x),read(y),Addedge(x,y);
  53. for(register int i=,x,y;i<=m;++i)read(x),read(y),Addquery(x,y),++d[x],++d[y];
  54. tarjan(,);dfs(,);
  55. return printf("%d\n",ans),;
  56. }

最后是非常蠢的一些错误记录:法1里面加边打错了。。该打。。。法2里面原来我tarjan求lca姿势一直是错的TuT,如果询问两个相同点就会GG,所以应当提前将vis置为1,然后查点对询问。

poj3417 Network/闇の連鎖[树上差分]的更多相关文章

  1. [POJ3417]Network/闇の連鎖

    Description 传说中的暗之连锁被人们称为 Dark. Dark 是人类内心的黑暗的产物,古今中外的勇者们都试图打倒它.经过研究,你发现 Dark 呈现无向图的结构,图中有 N 个节点和两类边 ...

  2. [POJ3417]Network(LCA,树上差分)

    Network Description Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried ...

  3. poj3417 闇の連鎖 【树上差分】By cellur925

    闇の連鎖(yam.pas/c/cpp)题目描述传说中的暗之连锁被人们称为 Dark.Dark 是人类内心的黑暗的产物,古今中外的勇者们都试图打倒它.经过研究,你发现 Dark 呈现无向图的结构,图中有 ...

  4. poj3417 Network 树上差分+LCA

    题目传送门 题目大意:给出一棵树,再给出m条非树边,先割掉一条树边,再割掉一条非树边,问有几种割法,使图变成两部分. 思路:每一条 非树边会和一部分的树边形成一个环,分三种情况: 对于那些没有形成环的 ...

  5. poj3417 Network——LCA+树上差分

    题目:http://poj.org/problem?id=3417 根据一条边被几个环覆盖来判断能不能删.有几种情况等: 用树上差分,终点 s++,LCA s-=2,统计时计算子树s值的和即可: 用S ...

  6. 【题解】POJ 3417 Network(倍增求LCA+DP+树上差分)

    POJ3417:http://poj.org/problem?id=3417 思路 我们注意到由“主要边”构成一颗树 “附加边”则是非树边 把一条附加边(x,y)加入树中 会与树上x,y之间构成一个环 ...

  7. [Codeforces 555E]Case of Computer Network(Tarjan求边-双连通分量+树上差分)

    [Codeforces 555E]Case of Computer Network(Tarjan求边-双连通分量+树上差分) 题面 给出一个无向图,以及q条有向路径.问是否存在一种给边定向的方案,使得 ...

  8. 【BZOJ-4326】运输计划 树链剖分 + 树上差分 + 二分

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 703  Solved: 461[Submit][Status] ...

  9. [luogu P3128][USACO15DEC]Max Flow [LCA][树上差分]

    题目描述 Farmer John has installed a new system of  pipes to transport milk between the  stalls in his b ...

随机推荐

  1. 宝塔配置composer默认的PHP版本

    当安装composer时,提示PHP版本问题: rm -f /usr/bin/php //这是默认的版本,删除 ln -sf /www/server/php/71/bin/php /usr/bin/p ...

  2. 移动端1px的边框

    我们知道,在移动端存在物理像素(physical pixel)和设备独立像素(density-independent pixel)的概念.物理像素也称为设备像素,它是显示设备中一个最微小的物理部件,每 ...

  3. 【Python】【demo实验29】【练习实例】【使用turtle画五角星】

    原题: 使用turtle画五角星: 我的代码: #!/usr/bin/python # encoding=utf-8 # -*- coding: UTF-8 -*- from turtle impor ...

  4. 利用requests提交相同名称数据的处理方法

    #字典键不能重复 data={ boardid' : boardid, 'divids[ ]' : '0' , 'divids[ ]' : '1' , 'divids[ ]' : '2' , } #这 ...

  5. Dreamoon and Strings CodeForces - 477C (字符串dp)

    大意: 给定字符串$s$, $p$, 对于$0\le x\le |s|$, 求$s$删除$x$个字符后, $p$在$s$中的最大出现次数. 显然答案是先递增后递减的, 那么问题就转化求最大出现次数为$ ...

  6. 进阶Java编程(6)正则表达式

    正则表达式 通过之前一系列的分析可以发现,String是一个非常万能的类型,因为String不仅仅可以支持有各种字符串的处理操作,也支持有向各个数据类型的转换功能,所以在项目的开发之中,只要用户输入的 ...

  7. QT 获取字体大小

    QFont font(androidFont); QFontInfo fInfo(font); qDebug()<<"FFFFFFFFFFFFFFFFFFFFFFFPPPSIZE ...

  8. 服务端相关知识学习(二)之Zookeeper可以干什么

    Zookeeper主要可以干哪些事情 配置管理,名字服务,提供分布式同步以及集群管理.那这些服务又到底是什么呢?我们为什么需要这样的服务?我们又为什么要使用Zookeeper来实现呢,使用Zookee ...

  9. 题解 UVA1316 【Supermarket】

    题目链接: https://www.luogu.org/problemnew/show/UVA1316 思路: 根据题目意思,我们需要用到贪心的思想,越晚过期的商品当然是越晚卖好.同时你假如有多个商品 ...

  10. 打包JavaFX11桌面应用程序

    打包JavaFX11桌面应用程序 这是JavaFX系列的第二弹,第一弹在这里 在第一弹中,我们使用的是OpenJDK8,但是OpenJDK8和Oracle Java JDK不一样,它没有内置JavaF ...