• HDU 3966 Aragorn's Story 树链拋分


    一、写在前面

      终于开始开坑link-cut-tree这个了,对于网上找到的大佬的前进路线,进行了一番研发,发现实际上可以实现对于树链拋分的制作。经历了若干长时间之后终于打了出来(为什么每次学什么东西都会强行写3遍左右。。。)

    二、题意

      阿拉贡同学发现一棵树装的若干营地有了若干敌人(可以是负数),这些敌人的变化情况会使用类似于“A-B之间的路上的所有营地都增加某个数量的人数”来进行。最后任意时间有询问:某个点当前有多少人?

    三、题解

      树链拋分的思路是这样的:首先把一棵树,对于每个节点都将会有:将子节点数量最多的一条链称为重链,其他各子节点各自组成以他们开头的重链。最终会使得一颗树的形状确定之后,就会唯一确定一个树链拋分方案(可能会在相同子节点的处理上有些分歧)。之后对于路径的寻找,会发现实际上,可以方便的找到任意一条路径,时间复杂度低于logN

    对于任意树链拋分代码需要以下几个数组:

    child代表某个节点为根节点的子节点的个数

    deep代表当前节点的深度

    number代表适用树链拋分的方式进行重新编号之后的映射

    fa代表父节点编号

    top当前重链的开头元素编号

    #include<bits/stdc++.h>
    using namespace std;
    
    #define veci vector<int>
    #define ll long long
    const long long MAXN=5e4+233;
    
    int arr[MAXN],child[MAXN],top[MAXN],deep[MAXN],tree[MAXN],fa[MAXN];
    veci G[MAXN];
    int number[MAXN];
    int n,m,p,size=1;
    
    void insert(int pos,int key)
    {
        while(pos<MAXN)
        {
            tree[pos]+=key;
            pos+=pos&(-pos);
        }
    //    cout<<pos<<endl;
    }
    
    ll getSum(int pos)
    {
        ll ans=0;
        while(pos)
        {
            ans+=tree[pos];
            pos-=pos&(-pos);
        }
        // cout<<"checkSum: "<<ans<<ends<<pos<<endl;
        return ans;
    }
    
    void dfs_1(int now,int last,int dep)
    {
        int len=G[now].size();
        fa[now]=last;
        deep[now]=dep;
        child[now]=1;
        for(int i=0;i<len;++i)
        {
            int tar=G[now][i];
            if(tar==last)continue;
            dfs_1(tar,now,dep+1);
            child[now]+=child[tar];
        }
    }
    
    void dfs(int now,int last,int first)
    {
        top[now]= first? first:now;
         // if(top[now]==now)
         // {
                // cout<<now<<" checked "<<endl;
         // }
        int len=G[now].size();
         // cout<<now<<"checkNum: "<<size<<endl;
        number[now]=size++;
        
        int maxx=-1;int pos=-1;
        for(int i=0;i<len;++i)
        {
            int tar=G[now][i];
            if(tar==last)continue;
            if(maxx<child[tar])
            {
                maxx=child[tar];
                pos=i;
            }
        }
        if(pos!=-1)dfs(G[now][pos],now,top[now]);
        for(int i=0;i<len;++i)
        {
            int tar=G[now][i];
            if(i==pos||tar==last)continue;
            dfs(tar,now,0);
        }
    }
    void update(int a,int b,int key)
    {
    //    cout<<"checkUP"<<a<<ends<<b<<ends<<key<<endl;
        int t1=top[a];
        int t2=top[b];
        // 
        while(t1!=t2)
        {
            
            if(deep[t1]<deep[t2])
            {
                swap(t1,t2);
                swap(a,b);
            }
            insert(number[t1],key);
            insert(number[a]+1,-key);
            // cout<<"checkTop: "<<t1<<ends<<a<<endl;
            a=fa[t1];
            // b=fa[t2];
            t1=top[a];
            // t2=top[b];
        }
        int star=min(number[a],number[b]);
        int endd=max(number[a],number[b])+1;
        // cout<<"check_line: "<<star<<ends<<endd<<endl;
        insert(star,key);
        insert(endd,-key);
    }
    
    int query(int a)
    {
        int pos=number[a];
        return getSum(pos)+arr[a];
    }
    
    void init()
    {
        size=1;
        for(int i=1;i<=n;++i)
        {
            G[i].clear();
            scanf("%d",&arr[i]);
        }
        memset(tree,0,4*(n+4));
        for(int i=1;i<n;++i)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            G[a].push_back(b);
            G[b].push_back(a);
        }dfs_1(1,0,0);
        dfs(1,0,0);
        for(int i=0;i<p;++i)
        {
            char c[2];
            scanf("%s",c);
            if(c[0]=='I')
            {
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                update(a,b,c);
                
            }else if(c[0]=='D')
            {
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                update(a,b,-c);
            }else if(c[0]=='Q')
            {
                int a;
                scanf("%d",&a);
                cout<<query(a)<<"
    ";
            }
        }
    }
    
    
    int main()
    {
    //    cin.sync_with_stdio(false);
        while(scanf("%d%d%d",&n,&m,&p)!=EOF)init();
        
        
        return 0;
    }
  • 相关阅读:
    10大在线编程网站
    Markdown使用简介 及 学习资源整理
    [Python]网络爬虫( 连载:大牛汪海 )
    Markdown指南
    并查集 (Union-Find Sets)及其应用
    C++ map<key , value> key值为指针
    【数据结构与算法】自己动手实现图的BFS和DFS(附完整源码)
    tornado 异步非阻塞
    NAT+穿洞基础知识梳理
    Appium入门
  • 原文地址:https://www.cnblogs.com/rikka/p/7904786.html
Copyright © 2020-2023  润新知