• FZOJ 2245 动态树(离散+离线+ 树状数组)


    Problem 2245 动态树

    Accept: 17    Submit: 82
    Time Limit: 3000 mSec    Memory Limit : 65536 KB

     Problem Description

    YellowStar拥有一棵神奇的动态树,该树由n个带权结点,n-1条边构成,任意两个结点互相可达,标号为i结点的权值为Wi。

    由于物质是运动的,这棵树每天都会发生一些变化,在第i天,该树权值在[l,r]的结点会发出强烈的光芒,YellowStar看到这一现象会非常的愉悦,它的愉悦值取决于:发光的这些结点构成了多少个连通子树。

    现在你知道动态树在接下来m天的发光情况,请你计算出YellowStar每一天的愉悦值

     Input

    第一行输入T,表示有T组样例(T <= 20)

    每组样例第一行为n,表示树的结点个数(1 <= n <= 1e5)

    接下来n个数字W1, W2, ... , Wn (1 <= Wi <= 1e9)表示每个结点的权值

    接下来n - 1行,每一行两个数字u, v (1 <= u, v <= n)表示树边

    接下来一个数字m(1 <= m <= 1e5),表示m天

    接下来m个询问,每个询问一行l, r (1 <= l <= r <= 1e9)表示每一天发光的结点的权值区间

     Output

    每组样例输出m行,表示YellowStar在这m天的愉悦值

     Sample Input

    1 3 1 3 2 1 2 1 3 3 1 3 1 2 2 3

     Sample Output

    1 1 2

     Hint

    long long类型请用%I64d输出

     Source

    FOJ有奖月赛-2017年4月(校赛热身赛)
    【分析】给你一棵树,每个节点有一个权值([1,1e9]),然后Q次询问,每次给出一个区间[l,r],问权值处在这个区间内的节点构成的联通块有多少个。
     一开始想到的是并查集+莫队,后来发现并查集那边不好处理。听了学长的,先将所有权值离散,区间离线,按照右端点从小到大排序。然后对于,每一条边,也看成一个区间
    跟前面一样排序。然后,对于一次查询区间,这个区间里有多少点这个我们是可以预处理出来的,假设是S个,也就是没有边的时候联通块是S个,若其中有两个点连有一条边,
    那么联通块-1,有多少边,S就减多少。现在的问题转化成了查询区间内有多少边。由于我们是排了序的,所以我们固定查询的右端点,对于右端点<=查询右端点的边,用树状数组
    统计<=右端点的边有多少就行了。
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <string>
    #include <cstdlib>
    #include <iostream>
    #include <map>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int>pii;
    const int N = 1e5+5;
    const double eps = 1e-8;
    int T,n,w[N],sum[N<<2],p[N<<2],cnt,m,ret[N],c[N<<2];
    struct Query{
      int l,r,id;
      bool operator<(const Query &rhs)const{
          return r<rhs.r;
      }
    }q[N],t[N];
    void add(int x){
       for(;x<=cnt;x+=x&-x)++c[x];
    }
    int ask(int x){
       int ret = 0;
       for(;x>0;x-=x&-x)ret+=c[x];
       return ret;
    }
    int main() {
       scanf("%d",&T);
       while(T--){
         scanf("%d",&n);
         cnt = 0;
         for(int i=1;i<=n;++i){
           scanf("%d",&w[i]);
           p[++cnt]=w[i];
         } 
         for(int i=1;i<n;++i){
            scanf("%d%d",&t[i].l,&t[i].r);
            t[i].l=w[t[i].l];
            t[i].r=w[t[i].r];
         }
         scanf("%d",&m);
         for(int i=1;i<=m;++i){
            scanf("%d%d",&q[i].l,&q[i].r);
            p[++cnt]=q[i].l;
            p[++cnt]=q[i].r;
            q[i].id=i;
         }
         sort(p+1,p+1+cnt);
         cnt=unique(p+1,p+1+cnt)-p-1;
         for(int i=0;i<=cnt;++i)c[i]=sum[i]=0;
         for(int i=1;i<=n;++i){
            w[i]=lower_bound(p+1,p+1+cnt,w[i])-p;
            ++sum[w[i]];
         }
         for(int i=1;i<=cnt;++i)sum[i]+=sum[i-1];
         for(int i=1;i<n;++i){
            t[i].l=lower_bound(p+1,p+1+cnt,t[i].l)-p;
            t[i].r=lower_bound(p+1,p+1+cnt,t[i].r)-p;
            if(t[i].l>t[i].r)swap(t[i].l,t[i].r);
         }
         for(int i=1;i<=m;++i){
            q[i].l=lower_bound(p+1,p+1+cnt,q[i].l)-p;
            q[i].r=lower_bound(p+1,p+1+cnt,q[i].r)-p;
         }
         if(n!=1)sort(t+1,t+1+n-1);
         sort(q+1,q+1+m);
         int j=1;
         for(int i=1;i<=m;++i){
           ret[q[i].id]=sum[q[i].r]-sum[q[i].l-1];
           for(;j<=n-1&&t[j].r<=q[i].r;++j)add(t[j].l);
           ret[q[i].id]-=ask(q[i].r)-ask(q[i].l-1);
         }
         for(int i=1;i<=m;++i)printf("%d
    ",ret[i]); 
       }
       return 0;
    }
     
  • 相关阅读:
    Linux学习-汇总
    前端学习-汇总
    人生苦短,我用python
    python_面试题_DB相关问题
    企业应用学习-git学习
    python基础-并发编程之I/O模型基础
    python_面试题_HTTP基础相关问题
    python_面试题_TCP的三次握手与四次挥手问题
    好的RESTful API的设计原则
    CSP-S2021 游记
  • 原文地址:https://www.cnblogs.com/jianrenfang/p/6743198.html
Copyright © 2020-2023  润新知