Bytedance 2019 icpc Camp day4 b组 H Network(树上差分+路径hash)

3 篇文章 0 订阅
1 篇文章 0 订阅

题意:有一个n个点m条边的无向图,需要任意割两条边使图不连通。求方案数。

假设我们有了图的任意一个生成树,易知答案一共由三个部分贡献

  1. 如果某两个点只被某两条边同时覆盖,那么同时删去这两条边;
  2. 如果任意一条由根出发的路径上,如果任意两条树边它们被其他边覆盖情况是一样的,那么我们可以把这两条树边删去中间部分就会变得与原图不连通;
  3. 桥+任意一条边。

其中1和3只要随便做一次树上差分跑个dfs就可以统计贡献。难点是我们如何维护任意树边被其他边的覆盖情况。

我们可以对路径hash

  • 像查分一样在路径两端+-上一个随机值,或者同时亦或上一个随机值(推荐使用后者,加和太容易冲突了)。
  • 两个树边的权值如果相同那么它们的被其他边覆盖的情况是一样的。

把上述情况全部加起来就是最终结果了。

#include<algorithm>
#include<vector>
#include<iostream>
#include<math.h>
#include<cstring>
#include<string>
#include<stack>
#include<map>
#include<set>
#include<unordered_map>
#include<queue>
#include <assert.h>

#define qcin; ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pb push_back
#define mp make_pair
#define clr(x) memset(x,0,sizeof x)
#define fmax(x) memset(x,0x3f,sizeof x)
#define finit(x) memset(x,-1,sizeof x)

#define dis(l,r) r-l+1
#define gstr(str) scanf("%s",str)
#define glen(str) strlen(str)
using namespace std;

typedef long long ll;

namespace Input
{
    const int BUF = 65536;
    char buf[BUF + 1];
    char *head = buf, *tail = buf;
}
inline char inputchar()
{
    using namespace Input;
    if(head == tail)
        *(tail = (head = buf) + fread(buf, 1, BUF, stdin)) = 0;
    return *head++;
}
inline void io(int &ret){
    char ch = inputchar();
    while(ch < '0' || ch > '9')
        ch = inputchar();
    ret = ch - '0';
    ch = inputchar();
    while(ch >= '0' && ch <= '9'){
        ret = ret * 10 + ch - '0';
        ch = inputchar();
    }
}
inline void sio(int &ret){
    ret = 0;
    char ch = inputchar();
    while((ch < '0' || ch > '9') && ch != '-')
        ch = inputchar();
    bool neg = false;
    if(ch == '-')
        neg = true, ch = inputchar();
    while(ch >= '0' && ch <= '9')
    {
        ret = ret * 10 + ch - '0';
        ch = inputchar();
    }
    if(neg)
        ret = -ret;
}

typedef pair<ll,ll>pll;
const int maxn = 5e5+10;
const ll mo = 2148473648;
typedef ll arr[maxn];
typedef char str[maxn];
void file(int x){if(x&&fopen("in.txt","r")){freopen("in.txt","r",stdin);if(x==2)freopen("1.txt","w",stdout);}}
struct Edge{
    int to,cst,nxt;
}E[maxn*10];

const double pi=acos(-1);
arr dfn,id,h,fa,dep,tree,num,hsh,a;
int n,tot,pos,m,st,cnt,bri;
void addedge(ll h[],int u,int v,int w=0){
    E[tot].to=v;
    E[tot].cst=w;
    E[tot].nxt=h[u];
    h[u]=tot++;
}

struct node {
    int u,v;
}e[maxn];

void dfs(int x,int d){
    dfn[x]=++pos,id[pos]=x;dep[x]=d;
    for(int i=h[x];~i;i=E[i].nxt){
        int y=E[i].to;
        if(!dfn[y]){
            tree[i>>1]=1;
            fa[y]=x;
            dfs(y,d+1);
        }
    }
}



void init(){
    clr(dfn);clr(tree);
    clr(num);clr(hsh);
    finit(h);
    tot=0;pos=0;
    cnt=0;bri=0;

}

unsigned long long last=0;

ll gethash(){
    last=(rand()*rand()<<2)+rand()+last;
    ll res=(last>>1);
    return res;
}


int main(){
    file(1);
    srand(time(NULL));
    int u,v,w;
    io(n),io(m);
    init();
    for(int i=0;i<m;i++){
        io(u),io(v);
        addedge(h,u,v);
        addedge(h,v,u);
        e[cnt++]={u,v};
    }

    dfs(1,1);
    for(int i=0;i<m;i++){
        if(tree[i])continue;
        int u=e[i].u;
        int v=e[i].v;
        if(dep[u]>dep[v])swap(u,v);
        ll w=gethash();
        assert(w>=0);
        num[u]--;hsh[u]^=w;
        num[v]++;hsh[v]^=w;
    }
    ll now=0,ans=0;
    for(int i=pos;i>1;i--){
        int p=id[i];
        num[fa[p]]+=num[p];
        hsh[fa[p]]^=hsh[p];
        if(!num[p])bri++;
        else {
            ans+=(num[p]==1);
            a[now++]=hsh[p];
        }
    }
    sort(a,a+now);
    ll tmp=1;
    for(int i=1;i<now;i++){
        if(a[i]==a[i-1])tmp++;
        else{
            ans+=tmp*(tmp-1)/2;
            tmp=1;
        }
    }
    ans+=tmp*(tmp-1)/2;
    ans+=bri*(m-bri);
    ans+=bri*(bri-1)/2;
    printf("%lld\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值