暗之链锁

一道简简单单的差分。。已经身败名裂了。。

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 }
原文地址:https://www.cnblogs.com/Maplers/p/7241511.html