Description

无向图中有N个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark有N – 1条主要边,并且Dark的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark还有M条附加边。
你的任务是把Dark斩为不连通的两部分。一开始Dark的附加边都处于无敌状态,你只能选择一条主要边切断。一旦你切断了一条主要边,Dark就会进入防御模式,主要边会变为无敌的而附加边可以被切断。但是你的能力只能再切断Dark的一条附加边。现在你想要知道,一共有多少种方案可以击败Dark。注意,就算你第一步切断主要边之后就已经把Dark斩为两截,你也需要切断一条附加边才算击败了Dark。

Input

第一行包含两个整数N和M。
之后N – 1行,每行包括两个整数A和B,表示A和B之间有一条主要边。
之后M行以同样的格式给出附加边。

Output

输出一个整数表示答案。

Sample Input

4 1
1 2
2 3
1 4
3 4

Sample Output

3

Hint

对于20% 的数据,N≤100,M≤100。
对于100% 的数据,N≤100 000,M≤200 000。数据保证答案不超过2^31– 1。

题解:

对于每一条主要边,讨论被几条附加边覆盖

若没有附加边覆盖则去掉这条主要边后,DARK已经成了不连通的两部分,则只需切掉任意一条附加边,对答案贡献m

若被一条附加边覆盖,则去掉条主要边后必须去掉这条附加边,对答案贡献1

若被大于一条附加变覆盖,这不能被切成不连通的两部分

可以用每一个点代表与这个点的dad相连的边

做法一:树链剖分+线段树

每加入一条附加边时把两点之间的路径上的所有点在线段树中加上一,最后做n遍单点查询。

代码:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cstdlib>

#include<algorithm>

#include<cmath>

#include<queue>

#include<cctype>

#include<cfloat>

#include<vector>

#include<map>

#define ls o*2

#define rs o*2+1

#define mi int mid=(l+r)>>1

#define maxn 100010

using namespace std;

struct data{

  int nex,to;

}e[maxn*2];

int head[maxn],edge=0;

int top[maxn],deep[maxn],son[maxn],dad[maxn],size[maxn],sp[maxn];

bool co[maxn];int b[maxn*4],lazy[maxn*4],siz[4*maxn],n;

void build(int o,int l,int r)

{

  siz[o]=r-l+1;

  if(l==r) return;

  mi;

  build(ls,l,mid);

  build(rs,mid+1,r);

}

void add(int from,int to)

{

  e[++edge].nex=head[from];

  e[edge].to=to;

  head[from]=edge;

}

void dfs1(int x)

{

  if(co[x]) return;

  co[x]=1;

  size[x]=1;

  for(int i=head[x];i;i=e[i].nex)

    {

      int u=e[i].to;

      if(co[u])continue;

      dad[u]=x;

      deep[u]=deep[x]+1;

      dfs1(u);

      size[x]+=size[u];

      if(size[son[x]]<size[u]) son[x]=u;

    }

}

int de=0;

void dfs2(int x)

{

  if(co[x] || x==0) return;

  co[x]=1;

  sp[x]=++de;

  top[son[x]]=top[x];

  dfs2(son[x]);

  for(int i=head[x];i;i=e[i].nex)

    {

      int u=e[i].to;

      if(co[u] || u==son[x]) continue;

      top[u]=u;

      dfs2(u);

    }

}

void down(int o)

{

  b[ls]+=lazy[o]*siz[ls],b[rs]+=lazy[o]*siz[rs];

  lazy[ls]+=lazy[o],lazy[rs]+=lazy[o];

  lazy[o]=0;

}

void change(int o,int l,int r,int u,int v)

{

  if(l!=r) down(o);

  if(u>v) return;

  if(l>=u&&r<=v) {b[o]+=siz[o];lazy[o]+=1;return;}

  if(l>v || r<u) return;mi;

  if(v<=mid) change(ls,l,mid,u,v);

  else if(u>mid) change(rs,mid+1,r,u,v);

  else change(ls,l,mid,u,mid),change(rs,mid+1,r,mid+1,v);

}

void TREE_CUT(int x,int y)

{

  while(top[x]!=top[y]){

    if(deep[top[x]]>deep[top[y]]) change(1,1,n,sp[top[x]],sp[x]),x=dad[top[x]];

    else change(1,1,n,sp[top[y]],sp[y]),y=dad[top[y]];

  }

  if(deep[x]>deep[y]) swap(x,y);

  change(1,1,n,sp[x]+1,sp[y]);

}

int find(int o,int l,int r,int p)

{

  if(l!=r) down(o);

  if(l==r) return b[o];

  mi;

  if(p<=mid) return find(ls,l,mid,p);

  else return find(rs,mid+1,r,p);

}

int main()

{

  //freopen("!.in","r",stdin);

  //freopen("!.out","w",stdout);

  int m,x,y;

  scanf("%d%d",&n,&m);

  build(1,1,n);

  for(int i=1;i<n;i++)

    scanf("%d%d",&x,&y),add(x,y),add(y,x);

  top[1]=1,deep[1]=1,dad[1]=1;

  dfs1(1);memset(co,0,sizeof(co));dfs2(1);

  for(int i=1;i<=m;i++)

    scanf("%d%d",&x,&y),TREE_CUT(x,y);

  int ans=0;

  for(int i=2;i<=n;i++)

    {

      int op=find(1,1,n,sp[i]);

      if(op==1) ans+=1;

      if(op==0) ans+=m;

    }

  printf("%d\n",ans);

  return 0;

}

做法二:树链剖分+树上差分

注意到只有区间修改和单点查询,这很容易想到差分,只要将树剖成链,然后就和链上的差分一样的了。

代码:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cstdlib>

#include<algorithm>

#include<cmath>

#include<queue>

#include<cctype>

#include<cfloat>

#include<vector>

#include<map>

#define ls o*2

#define rs o*2+1

#define mi int mid=(l+r)>>1

#define maxn 100010

using namespace std;

struct data{

  int nex,to;

}e[maxn*2];

int head[maxn],edge=0;

int top[maxn],deep[maxn],son[maxn],dad[maxn],size[maxn],sp[maxn];

bool co[maxn];int b[maxn*4],lazy[maxn*4],siz[4*maxn],n,cha[maxn];

void add(int from,int to)

{

  e[++edge].nex=head[from];

  e[edge].to=to;

  head[from]=edge;

}

void dfs1(int x)

{

  if(co[x]) return;

  co[x]=1;

  size[x]=1;

  for(int i=head[x];i;i=e[i].nex)

    {

      int u=e[i].to;

      if(co[u])continue;

      dad[u]=x;

      deep[u]=deep[x]+1;

      dfs1(u);

      size[x]+=size[u];

      if(size[son[x]]<size[u]) son[x]=u;

    }

}

int de=0;

void dfs2(int x)

{

  if(co[x] || x==0) return;

  co[x]=1;

  sp[x]=++de;

  top[son[x]]=top[x];

  dfs2(son[x]);

  for(int i=head[x];i;i=e[i].nex)

    {

      int u=e[i].to;

      if(co[u] || u==son[x]) continue;

      top[u]=u;

      dfs2(u);

    }

}

void change(int x,int y)

{

  cha[x]++,cha[y+1]--;

}

void TREE_CUT(int x,int y)

{

  while(top[x]!=top[y]){

    if(deep[top[x]]>deep[top[y]]) change(sp[top[x]],sp[x]),x=dad[top[x]];

    else change(sp[top[y]],sp[y]),y=dad[top[y]];

  }

  if(deep[x]>deep[y]) swap(x,y);

  change(sp[x]+1,sp[y]);

}

int main()

{

 // freopen("!.in","r",stdin);

 // freopen("!.out","w",stdout);

  int m,x,y;

  scanf("%d%d",&n,&m);

  for(int i=1;i<n;i++)

    scanf("%d%d",&x,&y),add(x,y),add(y,x);

  top[1]=1,deep[1]=1,dad[1]=1;

  dfs1(1);memset(co,0,sizeof(co));dfs2(1);

  for(int i=1;i<=m;i++)

    scanf("%d%d",&x,&y),TREE_CUT(x,y);

  int ans=0;

  cha[1]=0;

  for(int i=2;i<=n;i++)

    {

      cha[i]+=cha[i-1];

      int op=cha[i];

      if(op==1) ans+=1;

      if(op==0) ans+=m;

    }

  printf("%d\n",ans);

  return 0;

}

DARK的锁链的更多相关文章

  1. Dark的项链(树链剖分)

    P2272 - Dark的锁链 Description 无向图中有N个节点和两类边,一类边被称为主要边,而另一类被称为附加边.Dark有N – 1条主要边,并且Dark的任意两个节点之间都存在一条只由 ...

  2. 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果(速度可实时)

    最新的效果见 :http://video.sina.com.cn/v/b/124538950-1254492273.html 可处理视频的示例:视频去雾效果 在图像去雾这个领域,几乎没有人不知道< ...

  3. 微信小程序想要的是无法监测的流量dark social

    “微信小程序”将带来什么样的变化?就单单的是一个超级Web app?还是只是为了给大家手机节省一些空间?腾讯想要的是高达70%以上的“无法监测的巨大流量”,称之为“dark social”(暗社交). ...

  4. MWeb 1.6 发布!Dark Mode、全文搜寻、发布到Wordpress、Evernote 等支持更新、编辑/预览视图模式等

    Dark Mode 使用 View - Dark Mode 或快捷键 CMD + Option + L 开启或关闭 Dark Mode.可以在设置中设置 Dark Mode 状态下编辑器所使用的样式, ...

  5. 在Visual Studio 2012 Blue theme下使用Dark theme的文本编辑器颜色设置

    Visual Studio 2012 默认提供了3种color theme: blue,light,和dark.其中dark的文本编辑器颜色设定很爽,可是整个菜单项加上一些小的窗口如Find Resu ...

  6. 保护眼睛,把常用软件的背景设置成Dark

    每天长时间使用电脑,很多软件的背景都是白色,久看对眼睛不好. 1)Google Chrome,WebDev/看新闻/看邮件/写博客.使用Stylish插件和Global Dark Style,效果相当 ...

  7. paper 105: 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果及其他

    在图像去雾这个领域,几乎没有人不知道<Single Image Haze Removal Using Dark Channel Prior>这篇文章,该文是2009年CVPR最佳论文.作者 ...

  8. How to change statusbar text color to dark on android 4.4

    Because I haven't enough votes, so post picture at here, thank you. Almost 2 weeks ago, I was search ...

  9. hdu 2988 Dark roads

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2988 Dark roads Description Economic times these days ...

随机推荐

  1. UUID错误

    在Archive项目时,出现了“Your build settings specify a provisioning profile with the UUID “”, however, no suc ...

  2. 理解volatile

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  3. python面向对象编程对象和实例的理解

    给你一个眼神,自己体会

  4. 无分类编址 CIDR (构成超网)

    划分子网在一定程度上缓解了因特网在发展中遇 到的困难.然而在 1992 年因特网仍然面临三个必 须尽早解决的问题,这就是: B 类地址在 1992 年已分配了近一半,眼看就要在 1994 年 3 月全 ...

  5. JAVA日常练习—程序输入string转化为int并求和

    实验结果如图:

  6. 利用nodejs监控文件变化并使用sftp上传到服务器

    很久没写博客了,因为最近在用react+express做一个自己的工具型网站(其实就是夺宝岛抢拍器) 然后因为经常要改动,而且又要放到服务器上进行测试.总是要webpack,然后手动把文件上传上去,不 ...

  7. 总结ASP.NET MVC Web Application中将数据显示到View中的几种方式

    当我们用ASP.NET MVC开发Web应用程序的时候,我们都是将需要呈现的数据通过"Controllers"传输到"View"当中,怎么去实现,下面我介绍一下 ...

  8. 如何通过注解Bean类来封装SQL插入语句

    整体思路是酱紫的: 给bean上注解说明该bean对应着数据库中哪张表,给每个bean的属性都注解说明各自对应着这张表的哪个字段. 通过类反射获取表名,通过逐个反射每个属性的getter方法,获取注解 ...

  9. iOS arc下控制某一文件为非arc

    选中文件加上编译参数 -fno-objc-arc即可.

  10. ThinkPHP5.0学习1 — 命名空间

    定义命名空间:namespace sp1: 访问命名空间:\sp1\somefunction(); 非限定名称访问方式     //访问当前命名空间内容:somefunction(); 限定名称访问方 ...