首页 > 其他 > 详细

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

时间:2020-05-15 14:31:41      阅读:40      评论:0      收藏:0      [点我收藏+]

题目链接

题解思路:题目给了一棵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 ‘\n‘
#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\n",ans[i]);
}

int main()
{
    int T=1;
    scanf("%d",&T);
    while(T--) solve();
}

 


 

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

原文:https://www.cnblogs.com/Mmasker/p/12894682.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!