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

    中文题意简单易懂 不再叙述

    题解: 很明显我们考虑到运用树上差分的思想 加入这个元素等于在u,v位置加入 删除等于在lca(u,v)和fa[lca(u,v)]的地方-1 这样问题就转化成 从叶子节点dfs将这些点操作 并查询区间num最大且vul最小的值即可 这样我们可以通过线段树维护 然后本题的一个难点就是线段树合并了吧 讲道理 以前的合并的题都是启发式合并 但是这个题有个性质就是你用线段树维护 那么你就只需要将都有的节点从小到上更新 没有的之间连上去即可 然后就做完了  复杂度均摊下来应该是nlogn 空间复杂度同理也是nlogn

    #include <bits/stdc++.h>
    #define pii pair<int,int>
    const int MAXN=1e5+10;
    #define ll long long
    using namespace std;
    int n,m;
    vector<int>vec[MAXN];
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    int fa[MAXN],num[MAXN],dep[MAXN],son[MAXN];
    void dfs1(int v,int pre,int deep){
        num[v]=1;fa[v]=pre;dep[v]=deep+1;
        for(int i=0;i<vec[v].size();i++){
    	if(vec[v][i]!=pre){
    	    dfs1(vec[v][i],v,deep+1);
    	    num[v]+=num[vec[v][i]];
    	    if(son[v]==-1||num[son[v]]<num[vec[v][i]])son[v]=vec[v][i];
    	}
        }
    }
    int p[MAXN],fp[MAXN],cnt,tp[MAXN],sz;
    void dfs2(int v,int td){
        p[v]=++cnt;fp[p[v]]=v;tp[v]=td;
        if(son[v]!=-1)dfs2(son[v],td);
        for(int i=0;i<vec[v].size();i++){
    	if(vec[v][i]!=son[v]&&vec[v][i]!=fa[v])dfs2(vec[v][i],vec[v][i]);
        }
    }
    int Lca(int u,int v){
        int uu=tp[u];int vv=tp[v];
        while(uu!=vv){
    	if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v);
    	u=fa[uu];uu=tp[u];
        }
        if(dep[u]>dep[v])swap(u,v);
        return u;
    }
    typedef struct que{
        int u,v,c,lca;
    }que;
    que q[MAXN];
    vector<int>v1;
    vector<pii>v2[MAXN];
    typedef struct node{
        int num,maxx,l,r;
    }node;
    node d[MAXN*16*4];int ans[MAXN],rt[MAXN];
    void up(int x){
        if(!d[x].l&&!d[x].r)return ;
        d[x].num=0;
        if(d[x].l){d[x].num=d[d[x].l].num;d[x].maxx=d[d[x].l].maxx;}
        if(d[x].r){
    	if(!d[x].num)d[x].num=d[d[x].r].num,d[x].maxx=d[d[x].r].maxx;
    	else {
    	    if(d[x].num<d[d[x].r].num)d[x].num=d[d[x].r].num,d[x].maxx=d[d[x].r].maxx;
    	    else if(d[x].num==d[d[x].r].num)d[x].maxx=min(d[x].maxx,d[d[x].r].maxx);
    	}
        }
    }
    int cnt1;
    void update(int &rt,int l,int r,int t,int vul){
        if(!rt)rt=++cnt1;   
        if(l==r){d[rt].num+=vul;d[rt].maxx=l;return ;}
        int mid=(l+r)>>1;
        if(t<=mid)update(d[rt].l,l,mid,t,vul);
        else update(d[rt].r,mid+1,r,t,vul);
        up(rt);
    }
    void merge(int &x,int y,int l,int r){
        if(!x&&!y)return ;
        if(x&&y){
    	if(l==r){
    	    d[x].num+=d[y].num;return ;
    	}
    	int mid=(l+r)>>1;
    	merge(d[x].l,d[y].l,l,mid);
    	merge(d[x].r,d[y].r,mid+1,r);
        }
        else{
    	if(y)x=y;
    	return ;
        }
        up(x);
    }
    void dfs(int v){
        for(int i=0;i<vec[v].size();i++){
    	if(vec[v][i]!=fa[v]){
    	    dfs(vec[v][i]);
    	    merge(rt[v],rt[vec[v][i]],1,sz);
    	}
        }
        for(int i=0;i<v2[v].size();i++){
    	update(rt[v],1,sz,v2[v][i].first,v2[v][i].second);}
       // cout<<d[rt[v]].num<<"====:::"<<" "<<v<<endl;
       // for(int i=0;i<v2[v].size();i++)cout<<v2[v][i].first<<" "<<v2[v][i].second<<endl;
        if(!d[rt[v]].num)ans[v]=0;
        else ans[v]=d[rt[v]].maxx;
    }
    int main(){
        n=read();m=read();
        for(int i=1;i<=n;i++)son[i]=-1;
        int u,v;
        for(int i=1;i<n;i++)u=read(),v=read(),vec[u].push_back(v),vec[v].push_back(u);
        dfs1(1,0,0);dfs2(1,1);
        for(int i=1;i<=m;i++)q[i].u=read(),q[i].v=read(),q[i].c=read(),v1.push_back(q[i].c),q[i].lca=Lca(q[i].u,q[i].v);
        //for(int i=1;i<=m;i++)cout<<q[i].lca<<" ";
        //cout<<endl;
        sort(v1.begin(),v1.end());
        sz=unique(v1.begin(),v1.end())-v1.begin();
     //   built(1,1,sz);
        for(int i=1;i<=m;i++){
    	q[i].c=lower_bound(v1.begin(),v1.begin()+sz,q[i].c)-v1.begin()+1,v2[q[i].u].push_back(make_pair(q[i].c,1));
    	v2[q[i].v].push_back(make_pair(q[i].c,1));v2[q[i].lca].push_back(make_pair(q[i].c,-1));
    	v2[fa[q[i].lca]].push_back(make_pair(q[i].c,-1));
        }
        dfs(1);
        for(int i=1;i<=n;i++){
    	if(!ans[i])puts("0");
    	else printf("%d
    ",v1[ans[i]-1]);
        }
        return 0;
    }
    

    3307: 雨天的尾巴

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1004  Solved: 400
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output


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

    Sample Input

    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

    Sample Output

    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<=10^9

  • 相关阅读:
    每日一题 为了工作 2020 0412 第四十一题
    每日一题 为了工作 2020 04011 第四十题
    每日一题 为了工作 2020 0410 第三十九题
    每日一题 为了工作 2020 0409 第三十八题
    每日一题 为了工作 2020 0408 第三十七题
    每日一题 为了工作 2020 0407 第三十六题
    每日一题 为了工作 2020 0406 第三十五题
    每日一题 为了工作 2020 0405 第三十四题
    学习总结(二十四)
    学习总结(二十三)
  • 原文地址:https://www.cnblogs.com/wang9897/p/9141393.html
Copyright © 2011-2022 走看看