@loj - 2496 @ "AHOI / HNOI2018" cancer


@description@

Once there was a malignant tumor.

Cancer recently discovered the secret of mass production of the cancer problem. Consider the following types of data structure that: a given array, required to support several weird modification operation (e.g., to a number in the same time interval plus + c, or the number of the square root of one section simultaneously), and supports and asked intervals. Cancer considered n such modifying operation, and are numbered 1 ... n. When the cancer to be a data structure that, he will modify the operation of a number of selected these out, and then out into a question.

Of course, this may not be out of the question have to do. By sophisticated mathematical reasoning, cancer reveals the relationship between these modifications: there are
m of "mutually exclusive" modify operation of the first i-ui and vi operating operations. When a title contains both ui and vi two operations, this question becomes not do. On the other hand, when a question does not contain any operation "mutually exclusive", the question is can do.
In addition, also we found a tumor law: m - n is a small number (see the description "data range" in), and any two communication operations are modified. Two modification operations a, b are connected, if and only if there are several operating t0, t1, ..., tl, so that t0 = a, tl = b, and for any 1 <= i <= l, t [ i] and t [i-1] are "mutually exclusive" modify operation.

One pair of "mutually exclusive" modification operation called exclusive right. Now cancer want to know, given the values ​​of n and m mutually exclusive right, he can out of a total of how many different channels of data structure that can do. Two different data structure that is, if and only if one of the actions which appear in a title, but the problem does not appear in another.

Input format
first row of positive integers n, m.
Next m lines of two positive integers u, v, represents a pair of "mutually exclusive" modify operation.

Output format
output line an integer representing the number of cancer may be different from the data structure that can do. This number may be large, so only the die output value 998,244,353.

Sample Input 1
. 3 2
. 1 2
2. 3
Sample Output 1
. 5
Sample Input 2
. 6. 8
. 1 2
. 1. 3
. 1. 4
2. 4
. 3. 5
. 4. 5
. 4. 6
. 1. 6
Sample output 2
16

And prompt data range
n <= 10 ^ 5, m <= n + 10.

@solution@

Well-known figure independent set problem can not be done, so we need to issue a reasonable search violence.

Casually done with dp 1 (i.e., a tree) - is noted that when m = n.
And m - n is small, which means that the whole tree of FIG. + Is a few non-tree edges.
Forget about up to about 11 non-tree edge, which is attached to the side 11 points up to 22 special.

So there is a bold idea: violence enumerate specific point is selected, and then the tree again O (n) do it again dp.
Violence appears to be part of the enumeration 2 ^ 22 kinds of state, in fact, each side will correspond to three states (one side attached to two possible points selected simultaneously), then only 11 kinds of violence enumeration ^ 3 status. Many small range.
So you can O (3 ^ 11 * n) to write this question of violence, about 70 minutes of good results.

If I can not recalculated every time the whole tree dp enough.
If the particular point of the original tree is divided into a number of unrelated communication block, and each block is affected only by communicating with one or two specific points like influence.
So I can pretreatment, do not have to enumerate each complete re-do it again dp.

Then we through some communication means is divided into several blocks these trees: use a virtual tree.
Building a virtual tree between the special points, a virtual tree point picture into several blocks communication. In this case, either side of a virtual tree corresponding to a communication block, or a block belonging to a communication point virtual tree jurisdiction.
Thus just need to do it again in the virtual tree tree dp, communicating information preprocessing block out as the edge weight / point to the right.
* Up to 22 virtual trees only two points, so you can easily over.

@accepted code@

#include<map>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define rep(G, x) for(Graph::edge *p=G.adj[x];p;p=p->nxt)
const int MAXN = 100000;
const int MOD = 998244353;
inline int add(int x, int y) {return (x + y)%MOD;}
inline int mul(int x, int y) {return 1LL*x*y%MOD;}
struct Graph{
    struct edge{
        int to, f[2][2];
        edge *nxt;
    }edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt;
    Graph() {ecnt = &edges[0];}
    void addedge(int u, int v) {
        edge *p = (++ecnt);
        p->to = v, p->nxt = adj[u], adj[u] = p;
        p = (++ecnt);
        p->to = u, p->nxt = adj[v], adj[v] = p;
//      printf("! %d %d\n", u, v);
    }
}G1, G2;
int fa[20][MAXN + 5], dep[MAXN + 5], tid[MAXN + 5], dcnt = 0;
void dfs(int x, int f) {
    fa[0][x] = f, tid[x] = (++dcnt);
    for(int i=1;i<20;i++)
        fa[i][x] = fa[i-1][fa[i-1][x]];
    dep[x] = dep[f] + 1;
    rep(G1, x) {
        if( p->to == f ) continue;
        dfs(p->to, x);
    }
}
int lca(int u, int v) {
    if( dep[u] < dep[v] ) swap(u, v);
    for(int i=19;i>=0;i--)
        if( dep[fa[i][u]] >= dep[v] )
            u = fa[i][u];
    if( u == v ) return u;
    for(int i=19;i>=0;i--)
        if( fa[i][u] != fa[i][v] )
            u = fa[i][u], v = fa[i][v];
    return fa[0][u];
}
int sfa[MAXN + 5];
int find(int x) {
    return sfa[x] = (sfa[x] == x ? x : find(sfa[x]));
}
bool unite(int x, int y) {
    int fx = find(x), fy = find(y);
    if( fx == fy ) return false;
    else {
        sfa[fx] = fy;
        return true;
    }
}
bool tag[MAXN + 5];
bool cmp(int x, int y) {return tid[x] < tid[y];}
vector<int>arr;
int stk[MAXN + 5], tp;
void insert(int x) {
    if( tp ) {
        int z = lca(stk[tp], x);
        while( tp ) {
            int y = stk[tp--]; tag[y] = true;
            if( !tp || dep[stk[tp]] < dep[z] ) {
                if( y != z ) G2.addedge(z, y);
                break;
            }
            else G2.addedge(stk[tp], y);
        }
        stk[++tp] = z;
    }
    stk[++tp] = x;
}
int build_vtree() {
    sort(arr.begin(), arr.end(), cmp);
    for(int i=0;i<arr.size();i++)
        insert(arr[i]);
    int ret;
    while( tp ) {
        ret = stk[tp--], tag[ret] = true;
        if( tp ) G2.addedge(stk[tp], ret);
    }
    return ret;
}
int dp[2][MAXN + 5];
void dfs2(int x) {
    tag[x] = true, dp[0][x] = dp[1][x] = 1;
    rep(G1, x) {
        if( !tag[p->to] ) {
            dfs2(p->to);
            dp[0][x] = mul(dp[0][x], add(dp[0][p->to], dp[1][p->to]));
            dp[1][x] = mul(dp[1][x], dp[0][p->to]);
        }
    }
}
void dfs3(int x, int f) {
    dp[0][x] = dp[1][x] = 1;
    rep(G1, x) {
        if( p->to != f ) {
            if( !tag[p->to] ) dfs3(p->to, x);
            dp[0][x] = mul(dp[0][x], add(dp[0][p->to], dp[1][p->to]));
            dp[1][x] = mul(dp[1][x], dp[0][p->to]);
        }
    }
}
void func1(int x, int y, int f[][2]) {
    int p = fa[0][y];
    if( p == x ) {
        f[0][0] = f[0][1] = f[1][0] = 1;
        return ;
    }
    dp[0][x] = 1, dp[1][x] = 0;
    dfs3(p, y), f[0][0] = add(dp[0][p], dp[1][p]), f[0][1] = dp[0][p];
    dp[0][x] = 0, dp[1][x] = 1;
    dfs3(p, y), f[1][0] = add(dp[0][p], dp[1][p]), f[1][1] = dp[0][p];
    dfs2(p);
}
int g[2][MAXN + 5];
void get_value(int x, int f) {
    rep(G2, x) {
        if( p->to == f ) continue;
        func1(x, p->to, p->f), get_value(p->to, x);
    }
    g[0][x] = g[1][x] = 1;
    rep(G1, x) {
        if( !tag[p->to] ) {
            dfs2(p->to);
            g[0][x] = mul(g[0][x], add(dp[0][p->to], dp[1][p->to]));
            g[1][x] = mul(g[1][x], dp[0][p->to]);
        }
    }
}
int clr[MAXN + 5], c[MAXN + 5], root, ans;
vector<int>vec[MAXN + 5];
void check(int x, int fa) {
    rep(G2, x) {
        if( p->to != fa )
            check(p->to, x);
    }
    if( clr[x] != -1 )
        dp[clr[x]][x] = g[clr[x]][x], dp[!clr[x]][x] = 0;
    else dp[0][x] = g[0][x], dp[1][x] = g[1][x];
    rep(G2, x) {
        if( p->to != fa ) {
            dp[0][x] = mul(dp[0][x], add(mul(p->f[0][0], dp[0][p->to]), mul(p->f[0][1], dp[1][p->to])));
            dp[1][x] = mul(dp[1][x], add(mul(p->f[1][0], dp[0][p->to]), mul(p->f[1][1], dp[1][p->to])));
        }
    }
}
void search(int d) {
    if( d == arr.size() ) {
        check(root, 0);
        ans = add(ans, add(dp[0][root], dp[1][root]));
        return ;
    }
    clr[arr[d]] = 0, search(d + 1);
    if( !c[arr[d]] ) {
        for(int i=0;i<vec[arr[d]].size();i++)
            c[vec[arr[d]][i]]++;
        clr[arr[d]] = 1, search(d + 1);
        for(int i=0;i<vec[arr[d]].size();i++)
            c[vec[arr[d]][i]]--;
    }
}
map<int, int>mp;
int index(int x) {
    if( mp.count(x) ) return mp[x];
    else {
        arr.push_back(x);
        return mp[x] = arr.size() - 1;
    }
}
int main() {
    int n, m; scanf("%d%d", &n, &m);
    for(int i=1;i<=n;i++) sfa[i] = i;
    for(int i=1;i<=m;i++) {
        int u, v; scanf("%d%d", &u, &v);
        if( unite(u, v) ) G1.addedge(u, v);
        else {
            index(u), index(v);
            vec[u].push_back(v);
            vec[v].push_back(u);
        }
    }
    if( m == n - 1 ) {
        dfs2(1), printf("%d\n", add(dp[0][1], dp[1][1]));
        return 0;
    }
    dfs(1, 0), root = build_vtree(), get_value(root, 0);
    for(int i=1;i<=n;i++) c[i] = 0, clr[i] = -1;
    search(0);
    printf("%d\n", ans);
}

@details@

While we are talking quite simple, but still write code 190 + lines.
So write violence is probably the most cost-effective choice.

Therefore distinction communication block belongs to a virtual tree edge in communication with the virtual block belongs to a point of the tree.

Guess you like

Origin www.cnblogs.com/Tiw-Air-OAO/p/11716779.html