数据结构例题1
题目
因为原本就是棵树,所以部分边组成的一定是森林,那么连通块个数等于点数减边数。
我们离线操作,把所有询问按\(r\)排序。
然后从小到大枚举右端点,当右端点从\(r-1\)扩展到\(r\)时,我们把所有编号大的一端为\(r\)的边的另一个端点加入树状数组。
对于右端点为\(r\)的询问,在树状数组中查询大于等于该询问\(l\)的和即可。
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
namespace IO
{
char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
void Put(char x){*oS++=x;if(oS==oT)Flush();}
int read(){int x=0;char ch=Get();while(ch>57||ch<48)ch=Get();while(ch>=48&&ch<=57)x=x*10+(ch^48),ch=Get();return x;}
void write(int x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('\n');}
}
using namespace IO;
int min(int a,int b){return a<b? a:b;}
int max(int a,int b){return a>b? a:b;}
const int N=200007;
int t[N],ans[N],n,m;
struct node{int l,r,id;}q[N];
vector<int>vec[N];
int operator<(node a,node b){return a.r<b.r;}
void add(int p){while(p<=n)++t[p],p+=p&-p;}
int ask(int p){int sum=0;while(p)sum+=t[p],p^=p&-p;return sum;}
int query(int p){return ask(n)-ask(p-1);}
int main()
{
n=read(),m=read();int u,v,i,p;
for(i=1;i<n;++i) u=read(),v=read(),vec[max(u,v)].pb(min(u,v));
for(i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;
sort(q+1,q+m+1);
for(i=1,p=0;i<=m;++i)
{
for(;p<=q[i].r;++p) for(int x:vec[p]) add(x);
ans[q[i].id]=q[i].r-q[i].l+1-query(q[i].l);
}
for(i=1;i<=m;++i) write(ans[i]);
return Flush(),0;
}