zoukankan      html  css  js  c++  java
  • XSY 1749 tree

    题目大意

    给定一棵基环树, 问你有多少条路径的长度(ge K).

    点数(le 10^5)

    Solution

    基环树分治模板题.

    我是这样做的: 加边的时候用并查集维护点的连通性, 少加入环上的一条边, 使得基环图变为树的形态.

    首先在树上进行一次常规的树分治. 我们能得到不经过被删除的一条边的满足要求的路径数量;

    然后我们根据被删去的边的两个端点找到环, 在环上求出经过被删去边的路径数量即可.

    #include <cstdio>
    #include <cctype>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    namespace Zeonfai
    {
        inline int getInt()
        {
            int a = 0, sgn = 1; char c;
            while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
            while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
            return a * sgn;
        }
    }
    const int N = (int)4e5;
    int n, m, len;
    int lp[2];
    long long ans;
    struct disjointSet
    {
        int pre[N + 1];
        inline void initialize() {for(int i = 1; i <= n; ++ i) pre[i] = i;}
        inline int access(int u)
        {
            if(pre[u] != u) pre[u] = access(pre[u]);
            return pre[u];
        }
    }st;
    struct segmentTree
    {
        struct node
        {
            node *suc[2];
            int sz;
            inline node() {for(int i = 0; i < 2; ++ i) suc[i] = NULL; sz = 0;}
        }*rt;
        void clear(node *u)
        {
            for(int i = 0; i < 2; ++ i) if(u->suc[i] != NULL) clear(u->suc[i]);
            delete u;
        }
        inline void clear()
        {
            if(rt != NULL) clear(rt); rt = NULL; // 记得要把rt复位, 否则就会乱套啦
        }
        node* modify(node *u, int L, int R, int pos, int dlt)
        {
            if(u == NULL) u = new node;
            u->sz += dlt;
            if(L == R) return u;
            if(pos <= L + R >> 1) u->suc[0] = modify(u->suc[0], L, L + R >> 1, pos, dlt);
            else u->suc[1] = modify(u->suc[1], (L + R >> 1) + 1, R, pos, dlt);
            return u;
        }
        inline void modify(int pos, int dlt)
        {
            rt = modify(rt, 1, n, pos, dlt);
        }
        int query(node *u, int L, int R, int pos)
        {
            if(u == NULL) return 0;
            if(L >= pos) return u->sz;
            if(pos > L + R >> 1) return query(u->suc[1], (L + R >> 1) + 1, R, pos);
            else return query(u->suc[0], L, L + R >> 1, pos) + query(u->suc[1], (L + R >> 1) + 1, R, pos);
        }
        inline int query(int pos)
        {
            return query(rt, 1, n, pos);
        }
    }seg;
    struct tree
    {
        struct node
        {
            vector<int> edg;
            int flg, mx, sz;
            int nxt, lst, len;
            inline node() {edg.clear(); flg = 0;}
        }nd[N + 1];
        inline void addEdge(int u, int v)
        {
            int rtU = st.access(u), rtV = st.access(v);
            if(rtU == rtV)
            {
                lp[0] = u, lp[1] = v;
                return;
            }
            st.pre[rtU] = rtV;
            nd[u].edg.push_back(v); nd[v].edg.push_back(u);
        }
        void getSize(int u, int pre)
        {
            // printf("%d
    ", u);
            nd[u].sz = 1; nd[u].mx = 0;
            for(auto v : nd[u].edg) if(v != pre && ! nd[v].flg) getSize(v, u), nd[u].sz += nd[v].sz, nd[u].mx = max(nd[v].sz, nd[u].mx);
            // for(vector<int>::iterator p = nd[u].edg.begin(); p != nd[u].edg.end(); ++ p)
                // if(*p != pre && ! nd[*p].flg) getSize(*p, u), nd[u].sz += nd[*p].sz, nd[u].mx = max(nd[*p].sz, nd[u].mx);
        }
        int getRoot(int u, int pre, int cen)
        {
            nd[u].mx = max(nd[u].mx, nd[cen].sz - nd[u].sz);
            int res = u;
            for(auto v : nd[u].edg) if(v != pre && ! nd[v].flg)
            {
                int cur = getRoot(v, u, cen);
                if(nd[cur].mx < nd[res].mx) res = cur;
            }
            return res;
        }
        void getAnswer(int u, int pre, int cur)
        {
            ans += seg.query(len - cur);
            for(auto v : nd[u].edg) if(v != pre && ! nd[v].flg) getAnswer(v, u, cur + 1);
        }
        void update(int u, int pre, int cur)
        {
            seg.modify(cur, 1);
            for(auto v : nd[u].edg) if(v != pre && ! nd[v].flg) update(v, u, cur + 1);
        }
        inline void work(int u)
        {
            getSize(u, -1);
            u = getRoot(u, -1, u); nd[u].flg = 1;
            seg.clear(); seg.modify(1, 1);
            for(auto v : nd[u].edg) if(! nd[v].flg)
            {
                getAnswer(v, u, 1);
                update(v, u, 2);
            }
            for(auto v : nd[u].edg) if(! nd[v].flg) work(v);
        }
        inline void work() {work(1);}
        int getLoop(int u, int pre)
        {
            nd[u].lst = pre; nd[u].nxt = -1;
            if(u == lp[1]) return u;
            for(auto v : nd[u].edg) if(v != pre && nd[u].nxt == -1) nd[u].nxt = getLoop(v, u);
            if(~ nd[u].nxt) return u;
            nd[u].lst = -1;
            return -1;
        }
        void getOutsideSize(int u, int pre, int cur, int opt)
        {
            seg.modify(cur, opt);
            for(auto v : nd[u].edg) if(v != pre) getOutsideSize(v, u, cur + 1, opt);
        }
        void getOutsideSize(int u, int cur)
        {
            seg.modify(cur, 1);
            nd[u].len = cur;
            for(auto v : nd[u].edg) if(v != nd[u].nxt && v != nd[u].lst) getOutsideSize(v, u, cur + 1, 1);
            if(~ nd[u].lst) getOutsideSize(nd[u].lst, cur + 1);
        }
        void getLoopAnswer(int u, int pre, int cur)
        {
            ans += seg.query(len - cur);
            for(auto v : nd[u].edg) if(v != pre) getLoopAnswer(v, u, cur + 1);
        }
        void getLoopAnswer(int u, int cur)
        {
            seg.modify(nd[u].len, -1);
            for(auto v : nd[u].edg) if(v != nd[u].nxt && v != nd[u].lst) getOutsideSize(v, u, nd[u].len + 1, -1);
            ans += seg.query(len - cur);
            for(auto v : nd[u].edg) if(v != nd[u].nxt && v != nd[u].lst) getLoopAnswer(v, u, cur + 1);
            if(~ nd[u].nxt) getLoopAnswer(nd[u].nxt, cur + 1);
        }
        inline void workOnLoop()
        {
            getLoop(lp[0], -1);
            seg.clear();
            getOutsideSize(lp[1], 1);
            getLoopAnswer(lp[0], 1);
        }
    }T;
    int main()
    {
    
    #ifndef ONLINE_JUDGE
    
        freopen("tree.in", "r", stdin);
        freopen("tree.out", "w", stdout);
    
    #endif
    
        using namespace Zeonfai;
        n = getInt(), m = getInt(), len = getInt();
        st.initialize();
        for(int i = 0, u, v; i < m; ++ i) u = getInt(), v = getInt(), T.addEdge(u, v);
        T.work();
        if(n == m) T.workOnLoop();
        printf("%lld
    ", ans);
    }
    
    
  • 相关阅读:
    【解决】Word 在试图打开文件时遇到错误 请尝试下列方法:* xxx * xxx * xxx
    【开源】简单4步搞定QQ登录,无需什么代码功底【无语言界限】
    [经验]无线鼠标和无线键盘真的不能用了?——雷柏的重生之路~
    Git技巧:右键菜单怎么去除?
    07.GitHub实战系列~7.Git之VS2013团队开发(如果不想了解git命令直接学这篇即可)
    Git异常:fatal: V1.0 cannot be resolved to branch.
    06.GitHub实战系列~6.过滤器过滤掉的文件如何上传
    Git异常:Cannot delete the branch 'test1' which you are currently on
    ElasticSearch查询 第四篇:匹配查询(Match)
    字符串的长度,是字符数量,还是字节数量?
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7515510.html
Copyright © 2011-2022 走看看