每次询问点的个数是r-l+1, 那么联通块个数就是总点数减去边的个数
考虑哪些边有贡献, 令边为l,r (l<r), 那么ql <= l < r <= qr 的边有贡献
有时静态区间, 然后就是主席树
#include<bits/stdc++.h>
#define N 200050
using namespace std;
struct Node{int ls,rs,val;}t[N*40];
int tot,rt[N];
vector<int> v[N];
int n,q;
void Build(int &x,int l,int r){
x = ++tot;
if(l==r) return;
int mid = (l+r) >> 1;
Build(t[x].ls, l, mid);
Build(t[x].rs, mid+1, r);
}
void Insert(int &x,int last,int l,int r,int pos){
x = ++tot; t[x] = t[last]; t[x].val++;
if(l==r) return;
int mid = (l+r) >> 1;
if(pos<=mid) Insert(t[x].ls, t[last].ls, l, mid, pos);
else Insert(t[x].rs, t[last].rs, mid+1, r, pos);
}
int Quary(int a,int b,int l,int r,int L,int R){
if(L<=l && r<=R) return t[a].val - t[b].val;
int mid = (l+r) >> 1, ans = 0;
if(L<=mid) ans += Quary(t[a].ls, t[b].ls, l, mid, L, R);
if(R>mid) ans += Quary(t[a].rs, t[b].rs, mid+1, r, L, R);
return ans;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<n;i++){
int x,y; scanf("%d%d",&x,&y);
if(x>y) swap(x,y);
v[x].push_back(y);
}
Build(rt[0], 1, n);
for(int i=1;i<=n;i++){
rt[i] = rt[i-1];
if(!v[i].size()) continue;
for(int j=0;j<v[i].size();j++){
Insert(rt[i], rt[i], 1, n, v[i][j]);
}
}
while(q--){
int ql,qr; scanf("%d%d",&ql,&qr);
printf("%d\n",qr-ql+1-Quary(rt[qr], rt[ql-1], 1, n, ql, qr));
} return 0;
}