• 雨天的尾巴


    考试的时候直接扎第一题上了这到题连暴力都没打出来T_T;

    心路历程:

    其实考试时候还是有可能做出来的,当然关键在能否想到线段树合并。

    当时想到了离散化(很慌没打出来。。。),树上差分,lca倍增,当时觉滴倍增很难打,一看n<100000,于是选择

    用向上标记法,然而少了一行代码,,,,爆零两行泪。。。

    现在看来倍增真是一点不难啊好打有好用,所以不要有为难情绪,刚就完了。(平日板子要多打记熟啊)

    之所以没想到线段树合并是因为当时真的没有透彻理解,

    所以新知识点还是要知道它能干什么,知道它的用处。

    离散化用来干掉1->10^9,考试的时候真的傻认为要是有10^9种不就完了吗,,,然后发现忘了还有m次操作这东东,所以z离散化后len最大也就m个卡掉了很多

    以前一个物品的题直接dfs,lca树上差分就行,现在有10^9个(离散后10^5个),空间时间不可能一个一个去维护所以 得用线段树合并。

    所以得离线来做(我承认现在才知道离线在线是嘛玩意。。丢人啊。。。)

    每个点有很多信息所以权值线段树用来优化空间(当然也能优化时间),对每个点动态开树插入和删除(lca,f[lca]),最后dfs,父亲合并儿子。

    所以需维护区间的maxcnt以及其id,在merge时就需要多传一下l,r(1,len),如果l==r更新maxx值和id,需要注意的是如果maxx<=0,id干成0(题目要求)。

    sd错误:merge时忘了加上root[x]=merge,如果root[x]=0,就会...炸。还有空间没开够得开到maxn*50。

    优化:插入时如果lca==x||lca==y,那就插入了一次删了一次所以干脆不插入。。。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=100050;
    bool mark[maxn];
    int n,m,t,ans[maxn],len;
    int kpx[maxn],kpy[maxn],kpz[maxn],turn[maxn];//离线离散化
    int deep[maxn],f[maxn][20];//倍增lca
    int sz,root[maxn],cnt[maxn*50],lc[maxn*50],rc[maxn*50],maxx[maxn*50],num[maxn*50];//线段树
    int head[maxn],cntn=1;
    struct node{
      int to,next;
    }line[maxn*2];
    void add(int x,int y)
    {
       line[cntn].to=y;
       line[cntn].next=head[x];
       head[x]=cntn++;
    }
    void dfs(int x)
    { 
        for(int i=head[x];i;i=line[i].next)
        {
        int v=line[i].to;
            if(!mark[v])
        {
            mark[v]=1;
                deep[v]=deep[x]+1;
            f[v][0]=x;
                for(int j=1;j<=t;j++)
                    f[v][j]=f[f[v][j-1]][j-1];
                dfs(v);
        }
        }
    }
    
    int ask(int x,int y)
    {
        if(deep[x]>deep[y]) swap(x,y);
        for(int j=t;j>=0;j--) 
           if(deep[f[y][j]]>=deep[x])  y=f[y][j];
        if(x==y) return x;
        for(int j=t;j>=0;j--)
        {
        if(f[x][j]!=f[y][j])
        {
            x=f[x][j];
            y=f[y][j];
        }
        }
        return f[x][0];
    }
    void insert(int &root,int l,int r,int x)
    {
        if(!root) root=++sz;
        cnt[root]++;
        if(l==r)
        {
        maxx[root]=cnt[root];
        num[root]=maxx[root]<=0?0:l;
        return;
        }
        int mid=(l+r)/2;
        if(x<=mid) insert(lc[root],l,mid,x);
        else insert(rc[root],mid+1,r,x);
        if(maxx[lc[root]]>=maxx[rc[root]])  maxx[root]=maxx[lc[root]],num[root]=num[lc[root]];
        else maxx[root]=maxx[rc[root]],num[root]=num[rc[root]];
    }
    void decrease(int &root,int l,int r,int x)
    {
        if(!root) root=++sz;
        cnt[root]--;
        if(l==r)
        {
        maxx[root]=cnt[root];
        num[root]=maxx[root]<=0?0:l;
        return;
        }
        int mid=(l+r)/2;
        if(x<=mid) decrease(lc[root],l,mid,x);
        else decrease(rc[root],mid+1,r,x);
        if(maxx[lc[root]]>=maxx[rc[root]])  maxx[root]=maxx[lc[root]],num[root]=num[lc[root]];
        else maxx[root]=maxx[rc[root]],num[root]=num[rc[root]];
    }
    int merge(int x,int y,int l,int r)
    {
        if(!x||!y)    return x+y;
        cnt[x]+=cnt[y];
        if(l==r)
        {
            maxx[x]=cnt[x];
        num[x]=maxx[x]<=0?0:l;
            return x;
        }
        int mid=(l+r)/2;
        lc[x]=merge(lc[x],lc[y],l,mid);
        rc[x]=merge(rc[x],rc[y],mid+1,r);
        if(maxx[lc[x]]>=maxx[rc[x]])  maxx[x]=maxx[lc[x]],num[x]=num[lc[x]];
        else maxx[x]=maxx[rc[x]],num[x]=num[rc[x]];
        return x;
    }
    void dfst(int x)
    {
        for(int i=head[x];i;i=line[i].next)
        {
        int v=line[i].to;
        if(!mark[v])
        {
            mark[v]=1;
            dfst(v);
            root[x]=merge(root[x],root[v],1,len);
        }
        }
        ans[x]=turn[num[root[x]]];
    }
    int main(){
       int x,y;
       scanf("%d%d",&n,&m);
       while( (1<<(t+1)) <=n) t++;
       for(int i=1;i<n;i++)
       {
        scanf("%d%d",&x,&y);
         add(x,y);
        add(y,x);
       }
       deep[1]=1;
       mark[1]=1;
       dfs(1);
       for(int i=1;i<=m;i++)
       {
          scanf("%d%d%d",&kpx[i],&kpy[i],&kpz[i]);
          turn[i]=kpz[i];
       }
       sort(turn+1,turn+1+m);
       len=unique(turn+1,turn+1+m)-(turn+1);
       for(int i=1;i<=m;i++)
       {
          kpz[i]=lower_bound(turn+1,turn+1+len,kpz[i])-turn;
       }
       for(int i=1;i<=m;i++)
       {
        x=ask(kpx[i],kpy[i]);
            if(x==kpx[i])
            {
            insert(root[ kpy[i] ],1,len,kpz[i]);
                decrease(root[ f[x][0] ],1,len,kpz[i]);
                continue;
            }
            if(x==kpy[i])
            {
                insert(root[ kpx[i] ],1,len,kpz[i]);
                decrease(root[ f[x][0] ],1,len,kpz[i]);
                continue;
            }
        insert(root[ kpx[i] ],1,len,kpz[i]);
            insert(root[ kpy[i] ],1,len,kpz[i]);
            decrease(root[x],1,len,kpz[i]);
            decrease(root[ f[x][0] ],1,len,kpz[i]);
       }
       memset(mark,0,sizeof(mark));
       mark[1]=1;
       dfst(1);
       for(int i=1;i<=n;i++)
       {
        printf("%d
    ",ans[i]);
       }
    }
     
  • 相关阅读:
    艾伟_转载:把事件当作对象进行传递 狼人:
    艾伟_转载:AOP in Asp.net MVC 狼人:
    艾伟_转载:基于.NET平台的Windows编程实战(一)——前言 狼人:
    艾伟_转载:闲说继承 狼人:
    艾伟_转载:面向对象封装了啥 狼人:
    艾伟_转载:LINQ to SQL、NHibernate比较(二) LINQ to SQL实例 狼人:
    艾伟_转载:我对NHibernate的感受(1):对延迟加载方式的误解 狼人:
    艾伟_转载:用C#编程合并多个WORD文档 狼人:
    艾伟_转载:基于.NET平台的Windows编程实战(二)—— 需求分析与数据库设计 狼人:
    艾伟_转载:从ASP.NET的PHP执行速度比较谈起 狼人:
  • 原文地址:https://www.cnblogs.com/three-D/p/11057979.html
Copyright © 2020-2023  润新知