• [BZOJ3307]:雨天的尾巴(LCA+树上差分+权值线段树)


    题目传送门


    题目描述

    N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于xy的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。


    输入格式

    第一行数字N,M
    接下来N-1行,每行两个数字a,b,表示ab间有一条边
    再接下来M行,每行三个数字x,y,z如题


    输出格式

    输出有N
    i行的数字表示第i个点存放最多的物品是哪一种,如果有
    多种物品的数量一样,输出编号最小的。如果某个点没有物品则输出0


    样例

    样例输入:

    20 50
    8 6
    10 6
    18 6
    20 10
    7 20
    2 18
    19 8
    1 6
    14 20
    16 10
    13 19
    3 14
    17 18
    11 19
    4 11
    15 14
    5 18
    9 10
    12 15
    11 14 87
    12 1 87
    14 3 84
    17 2 36
    6 5 93
    17 6 87
    10 14 93
    5 16 78
    6 15 93
    15 5 16
    11 8 50
    17 19 50
    5 4 87
    15 20 78
    1 17 50
    20 13 87
    7 15 22
    16 11 94
    19 8 87
    18 3 93
    13 13 87
    2 1 87
    2 6 22
    5 20 84
    10 12 93
    18 12 87
    16 10 93
    8 17 93
    14 7 36
    7 4 22
    5 9 87
    13 10 16
    20 11 50
    9 16 84
    10 17 16
    19 6 87
    12 2 36
    20 9 94
    9 2 84
    14 1 94
    5 5 94
    8 17 16
    12 8 36
    20 17 78
    12 18 50
    16 8 94
    2 19 36
    10 18 36
    14 19 50
    4 12 50

    (有点长……)

    样例输出:

    87
    36
    84
    22
    87
    87
    22
    50
    84
    87
    50
    36
    87
    93
    36
    94
    16
    87
    50
    50


    数据范围与提示

    1≤N,M≤100000
    1≤a,b,x,y≤N
    1≤z≤109


    题解

    看到这道题我首先想到了这道题:BZOJ3631

    对于上面这道题,如果你还没有思路的话可以看一下这篇博客:[BZOJ3631]:[JLOI2014]松鼠的新家(LCA+树上差分)

    然后,我就立马想到了先求出LCA然后进行树上差分,但是这两道题的区别在于,这道题的物品种类不止一个,而且数还不小,显然不能单纯的用树上差分来解决。

    于是考虑用权值线段树维护,先将物品种类排序,然后看利用树上差分更新权值线段树,之后递归合并统计答案即可。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct rec//存边
    {
    	int nxt;
    	int to;
    }e[200000];
    struct qwq//存操作
    {
    	int x;
    	int y;
    	int z;
    }question[100001]; 
    int head[100001],cnt;
    int fa[100001][20];
    int root[100001],trfal[10000001],trsum[10000001],ls[10000001],rs[10000001],sum,tot;
    int dfsv[100001];
    int depth[100001];
    int que[100001];
    bool cmp(qwq a,qwq b){return a.z<b.z;}//按物品排序问题
    void add(int x,int y)//建边
    {
    	e[++cnt].nxt=head[x];
    	e[cnt].to=y;
    	head[x]=cnt;
    }
    void dfs(int x)//dfs预处理父亲和深度
    {
    	dfsv[++dfsv[0]]=x;
        for(int i=head[x];i;i=e[i].nxt)
            if(e[i].to!=fa[x][0])
            {
    	        fa[e[i].to][0]=x;
    	        depth[e[i].to]=depth[x]+1;
    	        for(int j=1;j<=18;j++)
    				fa[e[i].to][j]=fa[fa[e[i].to][j-1]][j-1];
    	        dfs(e[i].to);
            }
    }
    int LCA(int x,int y)//倍增求LCA
    {
        if(depth[x]<depth[y])swap(x,y);
        for(int i=18;i>=0;i--)
            if(depth[fa[x][i]]>=depth[y])x=fa[x][i];
        if(x==y)return x;
        for(int i=18;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
            {
                x=fa[x][i]; 
                y=fa[y][i];
            }
        return fa[x][0];
    }
    void pushup(int x)
    {
        trfal[x]=max(trfal[ls[x]],trfal[rs[x]]);//维护的权值
        trsum[x]=(trfal[ls[x]]>=trfal[rs[x]])?trsum[ls[x]]:trsum[rs[x]];//哪种物品
    }
    void insert(int &x,int k,int fl,int l,int r)
    {
        if(!x)x=++tot;
        if(l==r)
        {
            trfal[x]+=fl;
    		trsum[x]=que[l];
            return;
        }
        int mid=(l+r)>>1;
        if(k<=mid)insert(ls[x],k,fl,l,mid);
        else insert(rs[x],k,fl,mid+1,r);
        pushup(x);
    }
    void ask(int &x,int fl,int l,int r)
    {
        if(!fl)return;
        if(!x)
        {
            x=fl;
            return;
        }
        if(l==r)
        {
            trfal[x]+=trfal[fl];
            return;
        }
        int mid=(l+r)>>1;
        ask(ls[x],ls[fl],l,mid);
    	ask(rs[x],rs[fl],mid+1,r);
        pushup(x);
    }
    int main()
    {
    	int n,m;
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)root[i]=i;
    	tot=n;
    	for(int i=1;i<n;i++)
    	{
    		int a,b;
    		scanf("%d%d",&a,&b);
    		add(a,b);
    		add(b,a);
    	}
    	depth[1]=1;
    	dfs(1);
    	for(int i=1;i<=m;i++)
    		scanf("%d%d%d",&question[i].x,&question[i].y,&question[i].z);
    	sort(question+1,question+m+1,cmp);
    	for(int i=1;i<=m;i++)
    	{
    		int lca=LCA(question[i].x,question[i].y);
    		if(question[i].z>question[i-1].z)que[++sum]=question[i].z;
    		insert(root[question[i].x],sum,1,1,m);//树上差分操作
    		insert(root[question[i].y],sum,1,1,m);
    		insert(root[lca],sum,-1,1,m);
    		if(lca!=1)insert(root[fa[lca][0]],sum,-1,1,m);
    	}
        for(int i=n;i>1;i--)
    		ask(root[fa[dfsv[i]][0]],root[dfsv[i]],1,m);
        for(int i=1;i<=n;i++)
    		printf("%d
    ",trsum[root[i]]);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    Java四种引用类型+ReferenceQueue+WeakHashMap
    浅谈怎样写好一篇(技术)博客?
    MySQL-5.7.14-WinX64安装配置详解
    网络编程梳理:Android网络基础知识复习
    Git时间:常用Git命令收集整理(持续更新)
    一些常见技术问题收集(二)持续更新
    开源库AndroidSwipeLayout分析(一),炫酷ItemView滑动呼出效果
    开源库AndroidSwipeLayout分析(二),SwipeLayout源码探究
    ES 基础操作
    pymongo
  • 原文地址:https://www.cnblogs.com/wzc521/p/11072292.html
Copyright © 2020-2023  润新知