• [题解]gdfzoj 733 | 2020提高训练9T1 | HDU6162


    传送门

    原题(我赛后才知道的)

    知识点:主席树,(LCA)

    题目大意:给定树上两点 (x) ,(y) ,求 (x)(y) 的简单路径上权值在 (l) , (r) 之间的数的和

    看到题目,首先可以想到权值主席树,将每个节点至根节点这一条链上的节点信息存下来

    对于节点 (u) ,可以从他的父亲节点处更新

    然后用 (LCA) 解决

    要点:

    1.权值需要离散化

    2.主席树码量较大,调试需要耐心

    1. (LCA) 最好用 (tarjan) 求,不要用倍增,不然容易 (MLE) (不要问我怎么知道的)

    4.记得开 (long) (long) !

    代码 ( (tarjan) (LCA) 版):
    
    #include<bits/stdc++.h>
    namespace my_std
    {
        using namespace std;
        #define int long long
        #define rep(i,a,b) for (int i=(a);i<=(b);i++)
        #define drep(i,a,b) for (int i=(a);i>=(b);i--)
        #define go(u) for (int i=head[(u)];i;i=e[i].nxt)
        #define pf printf
        #define writeln(x) write(x),putchar('
    ')
        #define writesp(x) write(x),putchar(' ')
        #define mem(x,v) memset(x,v,sizeof(x))
        typedef long long ll;
        const int INF=0x7fffffff;
        inline int read()
        {
            int sum=0,f=1;
            char c=0;
            while (!isdigit(c))
            {
                if (c=='-') f=-1;
                c=getchar();
            }
            while (isdigit(c))
            {
                sum=(sum<<1)+(sum<<3)+(c^48);
                c=getchar();
            }
            return sum*f;
        }
        void write(int k)
        {
            if (k<0) putchar('-'),k=-k;
            if (k>=10) write(k/10);
            putchar(k%10+'0');
        }
    }
    using namespace my_std;
    const int N=100010;
    struct Tree
    {
        struct point
        {
            int l,r,val;
        }tree[N*18];
        int cnt=0,T[N];
        inline void push_up(int node)
        {
        	tree[node].val=tree[tree[node].l].val+tree[tree[node].r].val;
        }
        inline int clone(int node)
        {
            tree[++cnt]=tree[node];
            return cnt;
        }
        void build(int &node,int start,int end)
        {
        	node=++cnt;
        	if (start==end) return;
        	int mid=(start+end)>>1;
        	build(tree[node].l,start,mid);
        	build(tree[node].r,mid+1,end);
        }
        void update(int &node,int last,int start,int end,int p,int val)
        {
            node=clone(last);
            tree[node].val+=val;
            if (start==end) return;
            int mid=(start+end)>>1;
            if (p<=mid) update(tree[node].l,tree[last].l,start,mid,p,val);
            else update(tree[node].r,tree[last].r,mid+1,end,p,val);
        }
        int query(int node,int start,int end,int l,int r)
        {
            if (start>r||end<l) return 0;
            if (start>=l&&end<=r) return tree[node].val;
            int mid=(start+end)>>1;
            int sum_left=query(tree[node].l,start,mid,l,r);
            int sum_right=query(tree[node].r,mid+1,end,l,r);
            return sum_left+sum_right;
        }
    }tree;
    struct edge
    {
        int to,nxt;
    }e[N<<1];
    struct qedge
    {
    	int to,nxt,lca;
    }qe[N<<1];
    int n,m,t,cnt,qcnt=1,head[N],qhead[N],fa[N];
    int a[N],val[N];
    inline void add(int u,int v)
    {
        e[++cnt].to=v;
        e[cnt].nxt=head[u];
        head[u]=cnt;
    }
    inline void addq(int u,int v)
    {
    	qe[++qcnt].to=v;
    	qe[qcnt].nxt=qhead[u];
    	qhead[u]=qcnt;
    }
    struct Query
    {
    	int u,v,l,r;
    	void get()
    	{
    		u=read(),v=read(),l=read(),r=read();
    		addq(u,v),addq(v,u);
    	}
    }p[N];
    bool vis[N];
    int f[N];
    inline int getfa(int x)
    {
    	if (fa[x]==x) return x;
    	return fa[x]=getfa(fa[x]);
    }
    void tarjan(int u)
    {
    	vis[u]=1;
    	fa[u]=u;
    	go(u)
    	{
    		int v=e[i].to;
    		if (vis[v])
    		{
    			f[u]=v;
    			continue;
    		}
    		tarjan(v);
    		fa[v]=u;
    	}
    	for (int i=qhead[u];i;i=qe[i].nxt)
    	{
    		int v=qe[i].to;
    		if (vis[v])
    		{
    			qe[i].lca=getfa(v);
    			qe[i^1].lca=qe[i].lca;
    		}
    	}
    }
    void get_tree(int u,int fa)
    {
        tree.update(tree.T[u],tree.T[fa],1,t,a[u],val[a[u]]);
        go(u)
        {
            int v=e[i].to;
            if (v==fa) continue;
            get_tree(v,u);
        }
    }
    inline void solve(int x,int y,int LCA,int l,int r)
    {
        int tmp1=tree.query(tree.T[x],1,t,l,r);
        int tmp2=tree.query(tree.T[y],1,t,l,r);
        int tmp3=tree.query(tree.T[LCA],1,t,l,r);
        int tmp4=tree.query(tree.T[f[LCA]],1,t,l,r);
        writesp(tmp1+tmp2-tmp3-tmp4);
    }
    signed main()
    {
        n=read();m=read();
        rep(i,1,n) a[i]=val[i]=read();
        rep(i,1,n-1)
        {
            int u=read(),v=read();
            add(u,v),add(v,u);
        }
        sort(val+1,val+n+1);
        t=unique(val+1,val+n+1)-val-1;
        rep(i,1,n) a[i]=upper_bound(val+1,val+t+1,a[i])-val-1;
        get_tree(1,0);
        rep(i,1,m) p[i].get();
        tarjan(1);
        rep(i,1,m)
        {
    		int u=p[i].u,v=p[i].v,l=p[i].l,r=p[i].r;
    		int lca=qe[i<<1].lca;
            l=lower_bound(val+1,val+t+1,l)-val;
            r=upper_bound(val+1,val+t+1,r)-val-1;
            if (l>r)
            {
            	writesp(0);
            	continue;
            }
            solve(u,v,lca,l,r);
        }
    }
    
    
    代码(倍增 (LCA) 版):
    
    #include<bits/stdc++.h>
    namespace my_std
    {
        using namespace std;
        #define int long long
        #define rep(i,a,b) for (int i=(a);i<=(b);i++)
        #define drep(i,a,b) for (int i=(a);i>=(b);i--)
        #define go(u) for (int i=head[(u)];i;i=e[i].nxt)
        #define pf printf
        #define writeln(x) write(x),putchar('
    ')
        #define writesp(x) write(x),putchar(' ')
        #define mem(x,v) memset(x,v,sizeof(x))
        typedef long long ll;
        const int INF=0x7fffffff;
        inline int read()
        {
            int sum=0,f=1;
            char c=0;
            while (!isdigit(c))
            {
                if (c=='-') f=-1;
                c=getchar();
            }
            while (isdigit(c))
            {
                sum=(sum<<1)+(sum<<3)+(c^48);
                c=getchar();
            }
            return sum*f;
        }
        void write(int k)
        {
            if (k<0) putchar('-'),k=-k;
            if (k>=10) write(k/10);
            putchar(k%10+'0');
        }
    }
    using namespace my_std;
    const int N=100010;
    struct Irelia
    {
        int id,val;
    }p[N];
    struct Tree
    {
        struct point
        {
            int l,r,val;
        }tree[N<<5];
        int cnt=0,T[N];
        int clone(int node)
        {
            tree[++cnt]=tree[node];
            return cnt;
        }
        void update(int &node,int last,int start,int end,int p,int val)
        {
            node=clone(last);
            tree[node].val+=val;
            if (start==end) return;
            int mid=(start+end)>>1;
            if (p<=mid) update(tree[node].l,tree[last].l,start,mid,p,val);
            else update(tree[node].r,tree[last].r,mid+1,end,p,val);
        }
        int query(int node,int start,int end,int l,int r)
        {
            if (start>r||end<l) return 0;
            if (start>=l&&end<=r) return tree[node].val;
            int mid=(start+end)>>1;
            int sum_left=query(tree[node].l,start,mid,l,r);
            int sum_right=query(tree[node].r,mid+1,end,l,r);
            return sum_left+sum_right;
        }
    }tree;
    struct edge
    {
        int to,nxt;
    }e[N<<1];
    int n,m,cnt,head[N],f[N][21],dep[N];
    int a[N],val[N],ln;
    void add(int u,int v)
    {
        e[++cnt].to=v;
        e[cnt].nxt=head[u];
        head[u]=cnt;
    }
    void dfs(int u,int fa)
    {
        dep[u]=dep[fa]+1;
        f[u][0]=fa;
        for (int i=1;(1<<i)<=dep[u];i++)
        {
            f[u][i]=f[f[u][i-1]][i-1];
        }
        go(u)
        {
            int v=e[i].to;
            if (v==fa) continue;
            dfs(v,u);
        }
    }
    int lca(int x,int y)
    {
        if (dep[x]<dep[y]) swap(x,y);
        drep(i,ln,0)
        {
            if (dep[f[x][i]]>=dep[y]) x=f[x][i];
            if (x==y) return x;
        }
        drep(i,ln,0)
        {
            if (f[x][i]!=f[y][i])
            {
                x=f[x][i];
                y=f[y][i];
            }
        }
        return f[x][0];
    }
    void get_tree(int u,int fa)
    {
        tree.update(tree.T[u],tree.T[fa],1,n,a[u],val[a[u]]);
        go(u)
        {
            int v=e[i].to;
            if (v==fa) continue;
            get_tree(v,u);
        }
    }
    void solve(int x,int y,int l,int r)
    {
        int LCA=lca(x,y);
        int ans=a[LCA]>=l&&a[LCA]<=r?val[a[LCA]]:0;
        int tmp1=tree.query(tree.T[x],1,n,l,r);
        int tmp2=tree.query(tree.T[y],1,n,l,r);
        int tmp3=tree.query(tree.T[LCA],1,n,l,r);
        writesp(tmp1+tmp2-(tmp3<<1)+ans);
    }
    signed main()
    {
        n=read();m=read();
        ln=log2(n);
        rep(i,1,n) a[i]=val[i]=read();
        rep(i,1,n-1)
        {
            int u=read(),v=read();
            add(u,v),add(v,u);
        }
        sort(val+1,val+n+1);
        int t=unique(val+1,val+n+1)-val-1;
        rep(i,1,n) a[i]=upper_bound(val+1,val+t+1,a[i])-val-1;
        dfs(1,0);get_tree(1,0);
        rep(i,1,m)
        {
            int u=read(),v=read(),l=read(),r=read();
            if (l>r)
            {
                writesp(0);
                continue;
            }
            l=lower_bound(val+1,val+t+1,l)-val;
            r=upper_bound(val+1,val+t+1,r)-val-1;
            solve(u,v,l,r);
        }
    }
    
    

    备注:听 (Frez) 学长说因为此题离线,还可以将查询分成 (0)(r) , (0)(l-1) 两部分,可以用线段树实现

    我太菜了.jpg

  • 相关阅读:
    为什么网站不被百度收录或收录清零?
    XmlSerializer序列化一组成员到文本文件
    windows phone不同页面间传值
    windows phone下进行Isolated的IO读写
    windows Phone 后退键历史的清除
    Window Phone ListBox的DataBinding:
    VGA的相关代码
    如何避免Quartus II自動將未宣告的信號視為wire?
    XINLINX约束心得
    VIM配置文件备份
  • 原文地址:https://www.cnblogs.com/ZHANG-SHENG-HAO/p/12514723.html
Copyright © 2020-2023  润新知