Codeforces Round #143 (Div. 2) (边双联通)

原创 2013年12月05日 21:37:04

C:

给你一个数列,可以给某个数加上1,最多可以加k次,问操作之后相同的数的个数最多是多少。

排完序可以二分答案是哪个数,也可以直接枚举维护一个左值,每次判断i到j是否可行。

D:

这么简单的题居然不是AB题。。

E:

给你一个无向图,每个点最多只在一个简单环中,问s到t有多少种路径,不能经过同一条边两次,走过的边的集合不同表示路径不同。

思路:

由于每个点最多只在一个简单环中,所以一个点到另一个点经过的环的个数为x则不同路径的种数为 2^x,这个想想还是很明显的。所以对原图进行边双联通缩点后求出树上的lca就可以解决了。

#include 
#include 
#include 
#include 
using namespace std;
#define pb push_back
typedef __int64 ll;

const int maxn = 100000 + 10;
const int mod = 1000000007 ;

struct Edge {
    int u, to, next, vis;
}edge[maxn<<1];

int head[maxn], dfn[maxn], low[maxn], st[maxn], cnt[maxn], belo[maxn];
int E, Time, top, getot, type;
ll fac[maxn];

struct GEEDGE {
    int u, to;
}geedge[maxn<<1];

void init() {
    memset(head, -1, sizeof(head));
    memset(dfn, 0, sizeof(dfn));
    E = Time = top = getot = type = 0;
}

void newedge(int u, int to) {
    edge[E].u = u;
    edge[E].to = to;
    edge[E].vis = 0;
    edge[E].next = head[u];
    head[u] = E++;
}

void tarjan(int u) {
    dfn[u] = low[u] = ++Time;
    st[++top] = u;
    for(int i = head[u];i != -1;i = edge[i].next) {
        if(edge[i].vis) continue;
        edge[i].vis = edge[i^1].vis = 1;
        int to = edge[i].to;
        if(!dfn[to]) {
            tarjan(to);
            low[u] = min(low[u], low[to]);
            if(low[to] > dfn[u]) {
                geedge[getot].u = u;
                geedge[getot++].to = to;
            }
        }
        else
            low[u] = min(low[u], low[to]);
    }
    if(dfn[u] == low[u]) {
        int to;
        type++;
        do {
            cnt[type]++;
            to = st[top--];
            belo[to] = type;
        }while(to != u);
    }
}

int tot, B[maxn<<1], F[maxn<<1], d[maxn<<1][20], pos[maxn<<1], isclr[maxn<<1], qq[maxn];

void RMQ_init(int n) {
    for(int i = 1;i <= n; i++) d[i][0] = B[i];
    for(int j = 1;(1< pos[b]) swap(a, b);
    int ans = RMQ(pos[a], pos[b]);
    return F[ans];
}

void dfs(int u) {
    dfn[u] = ++Time;
    B[++tot] = dfn[u];
    F[Time] = u;
    pos[u] = tot;
    for(int i = head[u];i != -1;i = edge[i].next) {
        int to = edge[i].to;
        if(!dfn[to]) {
            if(isclr[to])    qq[to] = qq[u] + 1;
            else    qq[to] = qq[u];
            dfs(to);
            B[++tot] = dfn[u];
        }
    }
}

int main() {
    init();
    fac[0] = 1;
    for(int i = 1;i <= 100000; i++)
        fac[i] = fac[i-1]*2%mod;
    int n, m, u, to;
    scanf("%d%d", &n, &m);
    for(int i = 0;i < m; i++) {
        scanf("%d%d", &u, &to);
        newedge(u, to);
        newedge(to, u);
    }
    for(int i = 1;i <= n; i++) if(!dfn[i])
        tarjan(i);
    memset(head, -1, sizeof(head));
    memset(dfn, 0, sizeof(dfn));
    E = Time = tot = 0;
    for(int i = 0;i < getot; i++) {
        u = belo[geedge[i].u]; to = belo[geedge[i].to];
        newedge(u, to);
        newedge(to, u);
    }
    for(int i = 1;i <= type; i++) if(cnt[i] > 1)
        isclr[i] = 1;
    if(isclr[1])    qq[1] = 1;
    else    qq[1] = 0;
    dfs(1);
    RMQ_init(tot);
    int q, x, y;
    scanf("%d", &q);
    while(q--) {
        scanf("%d%d", &x, &y);
        x = belo[x]; y = belo[y];
        int LCA = lca(x, y), ans;
        if(LCA == x) {
            ans = qq[y] - qq[x] + isclr[LCA];
        }
        else if(LCA == y)
            ans = qq[x] - qq[y] + isclr[LCA];
        else
            ans = qq[x] + qq[y] - qq[LCA]*2 + isclr[LCA];
        printf("%I64d\n", fac[ans]);
    }
    return 0;
}

相关文章推荐

Codeforces Round #143 (Div. 2)

­­­­­好吧…Rating在上次#141之后1756.#143只有DIv2于是就打酱油来了.最后一题Tarjan_LCA忘光光了,比赛完才写的. 前四题比较简单 Rank80   A: 水. ...

Codeforces Round #143 (Div. 2) C. To Add or Not to Add 胡搞

A piece of paper contains an array of n integers a1, a2, ..., an. Your task is to find a number th...

Codeforces Round #143 (Div. 2) B - Magic, Wizardry and Wonders 数学

Vasya the Great Magician and Conjurer loves all kinds of miracles and wizardry. In one wave of a mag...

Codeforces Round #143 (Div. 2) B. Magic, Wizardry and Wonders

B. Magic, Wizardry and Wonders time limit per test 2 seconds memory limit per test 256 m...

Codeforces Round #143 (Div. 2) (ABCD 思维场)

Codeforces Round #143 (Div. 2) (ABCD 思维场)

Codeforces Beta Round #89 (Div. 2)E题,给一联通的无向图,求确定每边的方向,使得任意两点可达

/* 题意:给一无向图,现在要确定每边的方向,使得任意两点可达,一定存在。 思想:用Tarjan算法求双连通分量,将深入的边与使low值变小的边存起来。其它还没确定的随便选个方向即可 */ #...

【Codeforces Round 364 (Div 2)F】【暴力 双连通分量求桥】Break Up n点m边最多割2边最小成本使得S与T不联通

F. Break Up time limit per test 3 seconds memory limit per test 256 megabytes input...

Codeforces Beta Round #95 (Div. 2) (点双联通)

D. Subway time limit per test 2 seconds memory limit per test 256 megabytes input ...
  • Tsaid
  • Tsaid
  • 2011年12月06日 23:04
  • 520

【Codeforces Round 375 (Div 2) E】【欧拉回路Fleury算法 或网络流】One-Way Reform 每条边定向使得最多的点满足入度=出度

E. One-Way Reform time limit per test 2 seconds memory limit per test 256 megabytes ...

codeforces round 377 div2 F Tourist Reform tarjan求边双连通分量

F. Tourist Reform time limit per test 4 seconds memory limit per test 256 megabytes input...
  • jijijix
  • jijijix
  • 2017年02月28日 22:36
  • 154
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Codeforces Round #143 (Div. 2) (边双联通)
举报原因:
原因补充:

(最多只允许输入30个字)