LCA树上差分(点覆盖&边覆盖)

问题描述

传说中的暗之连锁被人们称为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。

wa:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=1e5+5;
const int maxm=2e5+5;
inline int read(){
    int a=0;bool b=1;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=0;
        x=getchar();
    }
    while('0'<=x && x<='9'){
        a=(a<<3)+(a<<1)+x-'0';
        x=getchar();
    }
    return b ? a : -a ;
}
int first[maxn],next[maxm*2],to[maxm*2],edge_count=1;
inline void add(int x,int y){
    edge_count++;
    to[edge_count]=y;
    next[edge_count]=first[x];
    first[x]=edge_count;
}
int deep[maxn],maxdep,f[maxn][32],log[maxn];
void build(int u,int fa){
    for(int i=first[u];i;i=next[i]){
        int v=to[i];
        if(v==fa)continue;
        
        deep[v]=deep[u]+1;
        f[v][0]=u;
        maxdep=max(maxdep,deep[v]);
        build(v,u);
    }
}
int n,m,ans,mark[maxn],size[maxn];
inline void LCA_init(){
    for(int i=1;i<=log[maxdep];i++){
        for(int j=1;j<=n;j++){
            f[j][i]=f[ f[j][(i>>1)] ][ (i>>1) ];
        }
    }
}

inline int LCA(int x,int y){
    if(deep[y]>deep[x])swap(x,y);
    for(int i=log[ deep[x] ];i>=0;i--){
        if(deep[y]>=deep[ f[x][i] ])x=f[x][i];
    }
    if(x==y)return x;
    for(int i=log[ deep[x] ];i>=0;i--){
        if(f[x][i]!=f[y][i]){
            x=f[x][i];y=f[y][i];
        }
    }
    return f[x][0];
}

void dfs_two(int u,int fa){
    size[u]=(mark[fa]+size[fa]);
    printf("size[%d]%d\n",u,size[u]);
    if(fa){
        if(size[u]==1)ans++;
        else if(size[u]<1)ans+=m;
        
    }
    for(int i=first[u];i;i=next[i]){
        int v=to[i];
        if(v==fa)continue;
        dfs_two(v,u);
    }
}
int main()
{
    n=read();m=read();
log[1]=0;
for(int i=2;i<=n;i++)log[i]=log[ (i>>1) ]+1;
    for(int i=1,a,b;i<n;i++){
        a=read();b=read();
        add(a,b);add(b,a);
    }
    build(1,0);
    deep[1]=1;
    LCA_init();
    for(int i=1,a,b;i<=m;i++){
        a=read();b=read();
        int lca=LCA(a,b);
//错误原因分析:当前节点被覆盖次数转移的时候,应从儿子转移,否则就会无辜被父亲的其他儿子转移
//边覆盖时:lca到父亲的边并不能被覆盖,所以ans[lca]-=2;
if(lca==a){ mark[f[lca][0]]++;mark[b]--; } else if(lca==b){ mark[f[lca][0]]++;mark[a]--; } else { mark[f[lca][0]]++;mark[b]--;mark[a]--; } } dfs_two(1,0); printf("%d",ans); return 0; }

AC:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=1e5+5;
const int maxm=2e5+5;
inline int read(){
    int a=0;bool b=1;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=0;
        x=getchar();
    }
    while('0'<=x && x<='9'){
        a=(a<<3)+(a<<1)+x-'0';
        x=getchar();
    }
    return b ? a : -a ;
}
int first[maxn],next[maxm*2],to[maxm*2],edge_count=1;
inline void add(int x,int y){
    edge_count++;
    to[edge_count]=y;
    next[edge_count]=first[x];
    first[x]=edge_count;
}
int deep[maxn],maxdep,f[maxn][32],log[maxn];
void build(int u,int fa){
    for(int i=first[u];i;i=next[i]){
        int v=to[i];
        if(v==fa)continue;
        
        deep[v]=deep[u]+1;
        f[v][0]=u;
        maxdep=max(maxdep,deep[v]);
        build(v,u);
    }
}
int n,m,ans,size[maxn];
inline void LCA_init(){
    for(int i=1;i<=log[maxdep];i++){
        for(int j=1;j<=n;j++){
            f[j][i]=f[ f[j][(i>>1)] ][ (i>>1) ];
        }
    }
}
inline int LCA(int x,int y){
    if(deep[y]>deep[x])swap(x,y);
    for(int i=log[ deep[x] ];i>=0;i--){
        if(deep[y]<=deep[ f[x][i] ])x=f[x][i];
    }
    if(x==y)return x;
    //printf("%d %d \n",x,y);
    for(int i=log[ deep[x] ];i>=0;i--){
        if(f[x][i]!=f[y][i]){
            x=f[x][i];y=f[y][i];
        }
    }
    return f[x][0];
}

void dfs_two(int u,int fa){
    for(int i=first[u];i;i=next[i]){
        int v=to[i];
        if(v==fa)continue;
        dfs_two(v,u);
        
        size[u]+=size[v];
        
    //if(u==6)printf("%d " ,size[6]);
    }
    if(size[u]==1 && fa)ans++;
    else if(!size[u] && fa)ans+=m;
}
int main()
{
    n=read();m=read();
log[1]=0;
for(int i=2;i<=n;i++)log[i]=log[ (i>>1) ]+1;
    for(int i=1,a,b;i<n;i++){
        a=read();b=read();
        add(a,b);add(b,a);
    }    
    deep[1]=1;//
    build(1,0);

    LCA_init();
    for(int i=1,a,b;i<=m;i++){
        a=read();b=read();
        int lca=LCA(a,b);
        size[a]++;size[b]++;size[lca]-=2;//保证树上差分是以该节点为根的子树的后缀和(simple)
    }
    dfs_two(1,0);
    printf("%d",ans);
    return 0;
}

wa:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=3e5+5;
const int maxm=3e5+5;
inline int read(){
    int a=0;bool b=1;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=0;
        x=getchar();
    }
    while('0'<=x && x<='9'){
        a=(a<<3)+(a<<1)+x-'0';
        x=getchar();
    }
    return b ? a : -a ;
}
int first[maxn],next[maxm*2],to[maxm*2],edge_count=1;
inline void add(int x,int y){
    edge_count++;
    to[edge_count]=y;
    next[edge_count]=first[x];
    first[x]=edge_count;
}
int deep[maxn],maxdep,f[maxn][32],log[maxn];
void build(int u,int fa){
    for(int i=first[u];i;i=next[i]){
        int v=to[i];
        if(v==fa)continue;
        
        deep[v]=deep[u]+1;
        f[v][0]=u;
        maxdep=max(maxdep,deep[v]);
        build(v,u);
    }
}
int n,a[maxn],ans[maxn];
inline void LCA_init(){
    for(int i=1;i<=log[maxdep];i++){
        for(int j=1;j<=n;j++){
            f[j][i]=f[ f[j][i-1] ][i-1];
        }
    }
}
inline int LCA(int x,int y){
    if(deep[y]>deep[x])swap(x,y);
    for(int i=log[ deep[x] ];i>=0;i--){
        if(deep[y]<=deep[ f[x][i] ])x=f[x][i];
    }
    if(x==y)return x;
    for(int i=log[ deep[x] ];i>=0;i--){
        if(f[x][i]!=f[y][i]){
            x=f[x][i];y=f[y][i];
        }
    }
    return f[x][0];
}
inline void dfs(int u ,int fa){
    for(int i=first[u];i;i=next[i]){
        int v=to[i];
        if(v==fa)continue;
        dfs(v,u);
        ans[u]+=ans[v];
    }
}

int main(){
    n=read();
log[1]=0;
for(int i=2;i<=n;i++)log[i]=log[ (i>>1) ]+1;
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    for(int i=1,x,y;i<n;i++){
        x=read();y=read();
        add(x,y);add(y,x);
    }
    deep[1]=1;
    build(1,0);
    LCA_init();
    
    for(int i=2;i<=n;i++){
        int lca=LCA(a[i],a[i-1]);
//wrong_reason:点覆盖时,lca会被覆盖,所以不能简单的在lca_father上操作
//应该同时操作lca及其father
//或者说x到lca(x,y)权值+1,y到lca(x,y)( 不包括lca(x,y) )+1
ans[f[lca][
0]]-=2;ans[a[i]]++;ans[a[i-1]]++; } dfs(1,0); for(int i=1;i<=n;i++){ printf("%d\n",ans[i]-(i!=a[1])); } return 0; }

ac:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=3e5+5;
const int maxm=3e5+5;
inline int read(){
    int a=0;bool b=1;char x=getchar();
    while(x<'0'||'9'<x){
        if(x=='-')b=0;
        x=getchar();
    }
    while('0'<=x && x<='9'){
        a=(a<<3)+(a<<1)+x-'0';
        x=getchar();
    }
    return b ? a : -a ;
}
int first[maxn],next[maxm*2],to[maxm*2],edge_count=1;
inline void add(int x,int y){
    edge_count++;
    to[edge_count]=y;
    next[edge_count]=first[x];
    first[x]=edge_count;
}
int deep[maxn],maxdep,f[maxn][32],log[maxn];
void build(int u,int fa){
    for(int i=first[u];i;i=next[i]){
        int v=to[i];
        if(v==fa)continue;
        
        deep[v]=deep[u]+1;
        f[v][0]=u;
        maxdep=max(maxdep,deep[v]);
        build(v,u);
    }
}
int n,a[maxn],ans[maxn];
inline void LCA_init(){
    for(int i=1;i<=log[maxdep];i++){
        for(int j=1;j<=n;j++){
            f[j][i]=f[ f[j][i-1] ][i-1];
        }
    }
}
inline int LCA(int x,int y){
    if(deep[y]>deep[x])swap(x,y);
    for(int i=log[ deep[x] ];i>=0;i--){
        if(deep[y]<=deep[ f[x][i] ])x=f[x][i];
    }
    if(x==y)return x;
    for(int i=log[ deep[x] ];i>=0;i--){
        if(f[x][i]!=f[y][i]){
            x=f[x][i];y=f[y][i];
        }
    }
    return f[x][0];
}
inline void dfs(int u ,int fa){
    for(int i=first[u];i;i=next[i]){
        int v=to[i];
        if(v==fa)continue;
        dfs(v,u);
        ans[u]+=ans[v];
    }
}

int main(){
    n=read();
log[1]=0;
for(int i=2;i<=n;i++)log[i]=log[ (i>>1) ]+1;
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    for(int i=1,x,y;i<n;i++){
        x=read();y=read();
        add(x,y);add(y,x);
    }
    deep[1]=1;
    build(1,0);
    LCA_init();
    
    for(int i=2;i<=n;i++){
        int lca=LCA(a[i],a[i-1]);
        ans[f[lca][0]]--;
        ans[lca]--;
        ans[a[i]]++;
        ans[a[i-1]]++;
    }
    
    dfs(1,0);
    for(int i=1;i<=n;i++){
        printf("%d\n",ans[i]-(i!=a[1]));
    }
    return 0;
}

niop5012 运输计划

题目描述

输入

输出

提示

posted @ 2019-05-12 17:01  Tj1  阅读(358)  评论(0编辑  收藏  举报