一道简简单单的差分。。已经身败名裂了。。
2434. 暗之链锁
时间限制:1 s 内存限制:256 MB
【题目描述】
传说中的暗之连锁被人们称为Dark。Dark是人类内心的黑暗的产物,古今中外的勇者们都试图打倒它。经过研究,你发现Dark呈现无向图的结构,图中有N个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark有N – 1条主要边,并且Dark的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark还有M条附加边。
你的任务是把Dark斩为不连通的两部分。一开始Dark的附加边都处于无敌状态,你只能选择一条主要边切断。一旦你切断了一条主要边,Dark就会进入防御模式,主要边会变为无敌的而附加边可以被切断。但是你的能力只能再切断
Dark的一条附加边。现在你想要知道,一共有多少种方案可以击败Dark。注意,就算你第一步切断主要边之后就已经把Dark斩为两截,你也需要切断一条附加边才算击败了Dark。
【输入格式】
第一行包含两个整数N和M。
之后N – 1行,每行包括两个整数A和B,表示A和B之间有一条主要边。
之后M行以同样的格式给出附加边。
【输出格式】
输出一个整数表示答案。
【样例输入】
4 1
1 2
2 3
1 4
3 4
【样例输出】
3
【数据范围】
对于20% 的数据,N≤100,M≤100。
对于100% 的数据,N≤100 000,M≤200 000。数据保证答案不超过2^31– 1。
这道题主要用了树上差分的思想,运用单点更新来求前缀和,来简单的判断是否被经过。
我们先用树链剖分来求出附加边的lca(其实用其他的方法也可以,只不过树链剖分打得更熟一些)。
然后就进行差分:
若x,y为附加边所连的两个节点,那我们称从x到y的树边被覆盖,我们对边的两个节点权+1,其lca的权-2;
这样就用前缀和成功的可以求出来了!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int n,m,x,y,num; 7 int adj[100001]; 8 struct edge{ 9 int s,t,next; 10 }k[200001]; 11 int read(){ 12 int sum=0;char ch=getchar(); 13 while(ch<'0'||ch>'9') ch=getchar(); 14 while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();} 15 return sum; 16 } 17 void init(int s,int t){ 18 k[num].s=s;k[num].t=t; 19 k[num].next=adj[s];adj[s]=num++; 20 } 21 int fa[100001],dp[100001],son[100001],size[100001]; 22 void Dfs1(int x){ 23 son[x]=0;size[x]=1; 24 for(int i=adj[x];i!=-1;i=k[i].next){ 25 int o=k[i].t; 26 if(o!=fa[x]){ 27 fa[o]=x;dp[o]=dp[x]+1; 28 Dfs1(o); 29 size[x]+=size[o]; 30 if(size[son[x]]<size[o]) 31 son[x]=o; 32 } 33 } 34 } 35 int top[100001],id[100001],pos[100001],cnt; 36 int fut[100001]; 37 void Dfs2(int u,int tp){ 38 top[u]=tp;id[u]=++cnt; 39 pos[cnt]=u; 40 if(son[u]) 41 Dfs2(son[u],tp); 42 for(int i=adj[u];i!=-1;i=k[i].next){ 43 int o=k[i].t; 44 if(o!=fa[u]&&o!=son[u]) 45 Dfs2(o,o); 46 } 47 fut[u]=cnt; 48 } 49 int sum[200001]; 50 int LCA(int x,int y){ 51 int fx=top[x],fy=top[y]; 52 while(fx^fy){ 53 if(dp[fx]<dp[fy]){ 54 swap(fx,fy); 55 swap(x,y); 56 } 57 x=fa[fx];fx=top[x]; 58 } 59 return dp[x]<dp[y]?x:y; 60 } 61 inline int lowbit(int i){ 62 return i&-i; 63 } 64 void update(int x,int z){ 65 while(x<=n){ 66 sum[x]+=z; 67 x+=lowbit(x); 68 } 69 } 70 void change(int x,int y){ 71 int lca=LCA(x,y); 72 update(id[x],1); 73 update(id[y],1); 74 update(id[lca],-2); 75 } 76 int gsum(int x){ 77 int ans=0; 78 while(x){ 79 ans+=sum[x]; 80 x-=lowbit(x); 81 } 82 return ans; 83 } 84 int ask(int x){ 85 return gsum(fut[x])-gsum(id[x]-1); 86 } 87 int main(){ 88 freopen("yam.in","r",stdin); 89 freopen("yam.out","w",stdout); 90 memset(adj,-1,sizeof(adj)); 91 n=read();m=read(); 92 for(int i=1;i<n;++i){ 93 x=read();y=read(); 94 init(x,y);init(y,x); 95 } 96 Dfs1(1);Dfs2(1,1); 97 for(int i=1;i<=m;++i){ 98 x=read();y=read(); 99 change(x,y); 100 } 101 int res=0; 102 for(int i=2;i<=n;++i){ 103 int q=ask(i); 104 if(q==1) 105 res++; 106 if(q==0) 107 res+=m; 108 } 109 printf("%d ",res); 110 // while(1); 111 return 0; 112 }