zoukankan      html  css  js  c++  java
  • 雨天的尾巴

    首先村落里的一共有n座房屋,并形成一个树状结构。然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x
    到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮。然后深绘里想知道,当所有的救济粮发放完毕后,每
    座房子里存放的最多的是哪种救济粮。
    1 <= n, m <= 100000, 1 <= a, b, x, y <= n, 1 <= z <= 100000

    //针对每个给出的树上的点,建立一个权值线段树,动态开点
    //权值线段树的叶子点,代表这个树上的点所存放的东西,及数量
     
    #include<bits/stdc++.h>
    #define mid ((l+r)>>1)
    using namespace std;
    const int N=100000+2;
    const int U=100001;
    int n,m;
    struct haha
    {
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y)
    {
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
    	hd[x]=cnt;
    }
    int fa[N][18];
    int dep[N];
    int ans[N];
    void dfs(int x,int d)
    {
        dep[x]=d;//x的深度为d,根结点深度为1 
        for(int i=hd[x];i;i=e[i].nxt)
    	{
            int y=e[i].to;
    		if(y==fa[x][0]) 
    		    continue;
            fa[y][0]=x;
    		dfs(y,d+1);
        }
    }
    int lca(int x,int y)
    {
        if(dep[x]<dep[y]) 
    	   swap(x,y);
        for(int j=17;j>=0;j--)
    	{
            if(dep[fa[x][j]]>=dep[y]) x=fa[x][j];
        }
        if(x==y) return x;
        for(int j=17;j>=0;j--)
    	{
            if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
        }
    	return fa[x][0];
    }
    struct node
    {
        int mx,id;
        int ls,rs;
    }t[N*60];
    int tot;
    int rt[N];
    void pushup(int x)//上传标记 
    //mx最多数字的个数
    //id最多数字是哪一种 
    {
        if(t[x].ls&&t[x].rs)//如果有左右结点 
    	{
            t[x].mx=max(t[t[x].ls].mx,t[t[x].rs].mx);
            t[x].id=t[t[x].ls].mx>=t[t[x].rs].mx?t[t[x].ls].id:t[t[x].rs].id;
        }
        else 
    	    if(t[x].ls)
    		{
                    t[x].mx=t[t[x].ls].mx;
                    t[x].id=t[t[x].ls].id;
            }
            else 
    		    if(t[x].rs)
    			{
                        t[x].mx=t[t[x].rs].mx;
                        t[x].id=t[t[x].rs].id;
                }
    }
    void upda(int &x,int l,int r,int p,int c)
    //upda(rt[x],1,U,z,1);
    //x代表结点编号,l,r代表范围
    //p代表加入哪一种货物 
    //c代表所加的数量 
    {
        
        if(!x) 
    	   x=++tot;
        if(l==r) 
    	{
            t[x].id=l; //在线段树中编号为x的结点,所存放食品的种类 
    		t[x].mx+=c;//存放食品的数量 
            return;
        }
        if(p<=mid) //转到左子树更新 
    	    upda(t[x].ls,l,mid,p,c);
        else //转到右子树更新
    	     upda(t[x].rs,mid+1,r,p,c);
        pushup(x);
    }
    int merge(int x,int y,int l,int r)
    {
        if(!x||!y)
    	//哪个点不为0就返回哪个点的编号,如果同时为0就返回0 
    	//如果此处没有返回,则说明合并的结点不为空 
    	    return x|y;
        if(l==r)//到了叶子点,强行合并 
    	{
            t[x].mx+=t[y].mx;
        }
        else
    	{
                  t[x].ls=merge(t[x].ls,t[y].ls,l,mid);
    			  //左子树与左子树合并,返回得是结点的编号 
                  t[x].rs=merge(t[x].rs,t[y].rs,mid+1,r);
    			  //右子树与右子树合并 
                  pushup(x);//标记上传 
        }
        return x;
    }
    void sol(int x)
    //求出x点存放的物品,哪种编号的最多 
    {
        for(int i=hd[x];i;i=e[i].nxt)
    	{
            int y=e[i].to;
            if(y==fa[x][0]) continue;
            sol(y);
            rt[x]=merge(rt[x],rt[y],1,U);//与其子结点进行合并 
         
        }
        if(t[rt[x]].mx>0)
    	   ans[x]=t[rt[x]].id;
    }
    int main()
    {
        scanf("%d%d",&n,&m);int x,y;
        for(int i=1;i<=n-1;i++)
    	{
            scanf("%d%d",&x,&y);
    		add(x,y);
    		add(y,x);
        }
    	dfs(1,1);
        dep[0]=-1;
        for(int j=1;j<=17;j++)
            for(int i=1;i<=n;i++)
                 fa[i][j]=fa[fa[i][j-1]][j-1];
        int z;
        while(m--)
    	{
            scanf("%d%d%d",&x,&y,&z);
            int anc=lca(x,y);
            upda(rt[x],1,U,z,1); //对x这个端点,加1 
            upda(rt[y],1,U,z,1);//对y这个端点,加1
            upda(rt[anc],1,U,z,-1);//对lca减1 
            if(fa[anc][0])  //如果lca有父亲点,也要减1  
    		    upda(rt[fa[anc][0]],1,U,z,-1);
            
        }
        sol(1);
        for(int i=1;i<=n;i++)
    	{
            printf("%d
    ",ans[i]);
        }
    	return 0;
    }
    

      

  • 相关阅读:
    ubuntu 14.04 下试用Sublime Text 3
    闲来无事,温习一下快速排序法
    学艺不精,又被shell的管道给坑了
    ssh登录失败处理步骤
    linux文件权限整理
    使用ssh远程执行命令批量导出数据库到本地
    leetcode-easy-design-384 Shuffle an Array
    leetcode-easy-dynamic-198 House Robber-NO
    leetcode-easy-dynamic-53 Maximum Subarray
    leetcode-easy-dynamic-121 Best Time to Buy and Sell Stock
  • 原文地址:https://www.cnblogs.com/cutemush/p/11835492.html
Copyright © 2011-2022 走看看