• ZOJ 4008.Yet Another Tree Query Problem(问题模型转化+线段树离线处理)


    题目链接

    题解思路:题目给了一棵n个节点的数和q次询问,每次询问是询问[L,R]区间内有多少个连通块。由于是一棵树,连通块的数量=节点数-边数,在明白这点以后就可以开始思考了,节点数很简单,就等于R-L+1,那么最重要的就是求边数。由于q有2e5次询问,因此每次算边数必须在log一下的时间内计算。这里我们可以将问题转化,不再是求[L,R]内连通块的数量,而是去算总共n-1条边,有多少恰好被[L,R]包含。这时问题便简单了,我们只需要将每条边和询问先按右区间排序,再将同样右区间中的询问放在最后面,每经过一条边ans++,最后再减去左区间<L的边数即可。


    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    #define ls l,mid,rt<<1
    #define rs mid+1,r,rt<<1|1
    #define endl '
    '
    #define p4 puts("444")
    const int MAXN = 1e6+10;
    const double EPS = 1e-12;
    
    int n,q;
    int ans[MAXN],sum[MAXN];
    struct node{
        int l,r,sx,id;
    }a[MAXN];
    
    bool cmp(node aa,node bb){
        if(aa.r!=bb.r)return aa.r<bb.r;
        else return aa.sx<bb.sx;
    }
    
    void Build(int l,int r,int rt){
        if(l==r){
            sum[rt]=0;
            return ;
        }
        int mid=(l+r)/2;
        Build(ls);
        Build(rs);
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    
    void Update(int l,int r,int rt,int pos){
        if(pos==l&&l==r){
            sum[rt]++;
            return ;
        }
        int mid=(l+r)/2;
        if(pos<=mid)Update(ls,pos);
        else Update(rs,pos);
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    
    int Query(int l,int r,int rt,int pos){
        if(pos==0)return 0;
        if(pos>=r)return sum[rt];
        int mid=(l+r)/2,ans=0;
        ans+=Query(ls,pos);
        if(pos>mid)ans+=Query(rs,pos);
        return ans;
    }
    
    void solve(){
        scanf("%d %d",&n,&q);
        Build(1,n,1);
        for(int i=1;i<n+q;i++){
            scanf("%d %d",&a[i].l,&a[i].r);
            if(a[i].l>a[i].r)swap(a[i].l,a[i].r);
            a[i].id=i;
            if(i<n)a[i].sx=0;
            else a[i].sx=1;
        }
        sort(a+1,a+n+q,cmp);
        int now=0;
        for(int i=1;i<n+q;i++){
            if(!a[i].sx){
                now++;
                Update(1,n,1,a[i].l);
            }
            else {
                ans[a[i].id]=(a[i].r-a[i].l+1)-(now-Query(1,n,1,a[i].l-1));
                //cout<<" ### "<<now<<" "<<Query(1,n,1,a[i].l-1)<<endl;
            }
        }
        for(int i=n;i<n+q;i++)printf("%d
    ",ans[i]);
    }
    
    int main()
    {
        int T=1;
        scanf("%d",&T);
        while(T--) solve();
    }

  • 相关阅读:
    Android 原创新作 超级水平仪 发布
    幸运转盘v1.0 【附视频】我的Android原创处女作,请支持!
    Android中MediaPlayer播放音乐时自动中断的解决办法
    语音写字板 v1.01 我的第二个Android作品
    Eclipse导入Android项目的正确方法
    Silverlight中后台代码设置TreeView选定项的方法
    C#网络编程(基本概念和操作) Part.1
    C#网络编程(同步传输字符串) Part.2
    C#网络编程(接收文件) Part.5
    C#网络编程(异步传输字符串) Part.3
  • 原文地址:https://www.cnblogs.com/Mmasker/p/12894682.html
Copyright © 2020-2023  润新知