• test20180922 打铁的匠


    题意

    分析

    法一:吉司机线段树

    这是一个在线的(O( n + q cdot log^2 n))做法。
    考虑维护节点到根的权值前缀和cost,那么查询的时候区间减去子树根节点的cost就是价值。
    然后由于子树dfs序连续,转化成线段树的区间查询。

    对区间查询,分为4种情况:

    1. 最大值都无价值,答案为0
    2. 最大值有价值,但次大值以后都无价值,那么答案就是最大值价值乘以最大值个数
    3. 最小值有价值,那么所有的都有价值,答案是sum-cost*区间长
    4. 以上条件都不满足,递归处理
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<ctime>
    #include<iostream>
    #include<string>
    #include<vector>
    #include<list>
    #include<deque>
    #include<stack>
    #include<queue>
    #include<map>
    #include<set>
    #include<bitset>
    #include<algorithm>
    #include<complex>
    #pragma GCC optimize ("O0")
    using namespace std;
    template<class T> inline T read(T&x)
    {
        T data=0;
    	int w=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
    		if(ch=='-')
    			w=-1;
    		ch=getchar();
    	}
        while(isdigit(ch))
            data=10*data+ch-'0',ch=getchar();
        return x=data*w;
    }
    typedef long long ll;
    const int INF=0x7fffffff;
    
    const int MAXN=1e5+7;
    
    struct Edge
    {
    	int nx,to,w;
    }E[MAXN];
    int head[MAXN],ecnt;
    
    void addedge(int x,int y,int w)
    {
    	E[++ecnt].to=y,E[ecnt].w=w;
    	E[ecnt].nx=head[x],head[x]=ecnt;
    }
    
    int dfn[MAXN],siz[MAXN],cost[MAXN];
    int idx[MAXN],clk;
    
    void dfs(int x)
    {
    //	cerr<<"dfsing "<<x<<endl;
    	dfn[x]=++clk;
    	siz[x]=1;
    	idx[clk]=x;
    	for(int i=head[x];i;i=E[i].nx)
    	{
    		int y=E[i].to,w=E[i].w;
    		cost[y]=cost[x]+w;
    		dfs(y);
    		siz[x]+=siz[y];
    	}
    }
    
    int ql,qr,c,k;
    struct SegTree
    {
    	ll sumv[MAXN<<2];
    	int maxv[MAXN<<2],num[MAXN<<2],secv[MAXN<<2];
    	int minv[MAXN<<2];
    #define lson (now<<1)
    #define rson (now<<1|1)
    	void pushup(int now)
    	{
    		sumv[now]=sumv[lson]+sumv[rson];
    		maxv[now]=max(maxv[lson],maxv[rson]);
    		minv[now]=min(minv[lson],minv[rson]);
    		if(maxv[lson]==maxv[rson])
    		{
    			num[now]=num[lson]+num[rson];
    			secv[now]=max(secv[lson],secv[rson]);
    		}
    		else
    		{
    			num[now]=maxv[lson]>maxv[rson]?num[lson]:num[rson];
    			secv[now]=max(secv[lson],secv[rson]);
    			secv[now]=max(secv[now],min(maxv[lson],maxv[rson]));
    		}
    	}
    	
    	void build(int now,int l,int r)
    	{
    		if(l==r)
    		{
    			sumv[now]=cost[idx[l]];
    			maxv[now]=minv[now]=sumv[now];
    			num[now]=1;
    			secv[now]=-1;
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(lson,l,mid);
    		build(rson,mid+1,r);
    		pushup(now);
    	}
    	
    	ll query(int now,int l,int r)
    	{
    		if(ql<=l&&r<=qr)
    		{
    			if(maxv[now]<c+k)
    				return 0;
    			if(secv[now]<c+k)
    				return (ll)(maxv[now]-c)*num[now];
    			if(minv[now]>=c+k)
    				return sumv[now]-(ll)c*(r-l+1);
    		}
    		int mid=(l+r)>>1;
    		ll ans=0;
    		if(ql<=mid)
    			ans+=query(lson,l,mid);
    		if(qr>=mid+1)
    			ans+=query(rson,mid+1,r);
    		return ans;
    	}
    }T;
    
    int main()
    {
      freopen("forging.in","r",stdin);
      freopen("forging.out","w",stdout);
    	int n;
    	read(n);
    	for(int i=2;i<=n;++i) // edit 1:root has no father
    	{
    		static int fa,w;
    		read(fa);read(w);
    		addedge(fa,i,w);
    	}
    	dfs(1);
    	T.build(1,1,n);
    	int q;
    	read(q);
    	while(q--)
    	{
    		static int u;
    		read(u);read(k);
    		ql=dfn[u],qr=dfn[u]+siz[u]-1,c=cost[u];
    		printf("%lld
    ",T.query(1,1,n));
    	}
    //  fclose(stdin);
    //  fclose(stdout);
        return 0;
    }
    

    法二:平衡树

    题意是给定一棵带边权的有根树,每次询问一个点u的子树内与其距离至少是k的点到u的距离之和。
    容易想到如果我们能维护出每个点子树内点到其距离的有序表,询问将十分简单。我们将询问离线挂在每个点上,从下向上用平衡树维护每个点的子树内距离,合并时启发式合并。
    (O(n log^2 n + q log n))

    #include <bits/stdc++.h>
    
    using LL = long long;
    
    const int MAXN = 1e5 + 5;
    
    struct SplayTree {
        struct Node {
            Node *fa, *ch[2];
            LL sum, tag, val;
            int size;
            
            Node(LL _val): sum(_val), val(_val) {
                fa = ch[0] = ch[1] = 0;
                tag = 0;
                size = 1;
            }
            
            void Add(LL w) {
                val += w;
                sum += w * size;
                tag += w;
            }
            
            void Down() {
                for (int i = 0; i < 2; ++i) if (ch[i])
                    ch[i]->Add(tag);
                tag = 0;
            }
            
            void DownR() {
                if (fa) fa->DownR();
                Down();
            }
            
            void Update() {
                sum = val;
                size = 1;
                for (int i = 0; i < 2; ++i) if (ch[i]) {
                    sum += ch[i]->sum;
                    size += ch[i]->size;
                }
            }
            
            int Which() {
                return this == fa->ch[1];
            }
        } *root;
        
        SplayTree() = default;
        
        void Rotate(Node *k) {
            Node *p = k->fa;
            int l = k->Which(), r = l ^ 1;
            
            k->fa = p->fa;
            if (p->fa) p->fa->ch[p->Which()] = k;
            
            p->ch[l] = k->ch[r];
            if (k->ch[r]) k->ch[r]->fa = p;
            
            k->ch[r] = p;
            p->fa = k;
            
            p->Update();
            k->Update();
        }
        
        void Splay(Node *k, Node *aim_fa = 0) {
            k->DownR();
            
            while (k->fa != aim_fa) {
                Node *p = k->fa;
                if (p->fa != aim_fa) {
                    if (k->Which() ^ p->Which()) Rotate(k);
                    else Rotate(p);
                }
                Rotate(k);
            }
            
            if (!aim_fa) root = k;
        }
        
        void Insert(LL val, Node *&k, Node *fa = 0) {
            if (!k) {
                k = new Node(val);
                k->fa = fa;
                Splay(k);
                return;
            }
            k->Down();
            Insert(val, k->ch[val > k->val], k);
        }
        
        void Add(LL val) {
            root->Add(val);
        }
        
        void Traverse(std::vector<LL> &vec, Node *k) {
            if (!k) return;
            k->Down();
            Traverse(vec, k->ch[0]);
            vec.push_back(k->val);
            Traverse(vec, k->ch[1]);
        }
        
        void Delete(Node *&k) {
            if (!k) return;
            for (int i = 0; i < 2; ++i) Delete(k->ch[i]);
            delete k; k = 0;
        }
        
        void Merge(SplayTree &oth) {
            if (root->size < oth.root->size) std::swap(root, oth.root);
            
            // std::cerr << root->size << " " << oth.root->size << std::endl;
            
            std::vector<LL> list;
            oth.Traverse(list, oth.root);
            oth.Delete(oth.root);
            for (LL i: list)
                Insert(i, root);
        }
        
        LL Query(LL val) {
            Node *k = root, *p = 0;
            while (k) {
                k->Down();
                if (k->val < val) {
                    p = k;
                    k = k->ch[1];
                } else {
                    k = k->ch[0];
                }
            }
            if (!p) return root->sum;
            Splay(p);
            if (!root->ch[1]) {
                return 0;
            } else {
                return root->ch[1]->sum;
            }
        }
    } splay[MAXN];
    
    int n, q;
    std::vector<int> G[MAXN];
    int fa[MAXN], w[MAXN];
    
    std::vector<std::pair<int, int>> qry[MAXN];
    
    LL ans[MAXN];
    
    void DFS(int now) {
        splay[now].Insert(0, splay[now].root);
        for (int to: G[now]) {
            DFS(to);
            
            splay[to].Add(w[to]);
            splay[now].Merge(splay[to]);
        }
        
        for (auto i: qry[now]) {
            int k = i.first, idx = i.second;
            
            ans[idx] = splay[now].Query(k);
        }
    }
    
    void Main() {
    #ifndef LOCAL
        freopen("forging.in", "r", stdin);
        freopen("forging.out", "w", stdout);
    #endif
        
        scanf("%d", &n);
        for (int i = 2; i <= n; ++i) {
            scanf("%d%d", fa + i, w + i);
            G[fa[i]].push_back(i);
        }
        
        scanf("%d", &q);
        for (int i = 1; i <= q; ++i) {
            static int u, k;
            
            scanf("%d%d", &u, &k);
            qry[u].emplace_back(k, i);
        }
        
        DFS(1);
        
        for (int i = 1; i <= q; ++i)
            printf("%lld
    ", ans[i]);
    }
    
    register char *_sp __asm__("rsp");
    
    int main() {
        const int size = 32 << 20;
        static char *sys, *mine(new char[size] + size - 4096);
        sys = _sp; _sp = mine; Main(); _sp = sys;
        
        return 0;
    }
    
  • 相关阅读:
    【Java】Caused by: com.ibatis.sqlmap.client.SqlMapException: There is no statement named *** in this SqlMap.
    【Mac】Mac 使用 zsh 后, mvn 命令无效
    【Java】Exception thrown by the agent : java.rmi.server.ExportException: Port already in use: 1099
    【Android】drawable VS mipmap
    【Android】java.lang.SecurityException: getDeviceId: Neither user 10065 nor current process has android.permission.READ_PHONE_STATE
    java sql解析
    java动态编译
    随想
    一致hash算法
    一致性哈希算法及其在分布式系统中的应用
  • 原文地址:https://www.cnblogs.com/autoint/p/9708296.html
Copyright © 2020-2023  润新知