题面
2s,512mb
题解
如果有两对点 ( a , b ) , ( c , d ) (a,b),(c,d) (a,b),(c,d) LCA相同,且 c ≤ a ≤ b ≤ d c\leq a\leq b\leq d c≤a≤b≤d ,那么我们只需要保留 ( a , b ) (a,b) (a,b) 就够了。
我们用启发式合并 set 维护每个点的子树集合,合并的时候就可以处理出初步筛选的有效点对(小集合的每个点在大集合中找前驱后继),这时有效点对的总个数是 O ( n log n ) O(n\log n) O(nlogn) 的。
我们把 d e p ( l c a ( x , y ) ) dep(lca(x,y)) dep(lca(x,y)) 相等的所有点对 ( x , y ) (x,y) (x,y) 再进行筛选,得到互不包含的点对,此时就可以把询问离线下来,用扫描线添加点对。对于两个点对 ( a , c ) , ( b , d ) (a,c),(b,d) (a,c),(b,d) 若 a ≤ b ≤ c ≤ d a\leq b\leq c\leq d a≤b≤c≤d ,那么 ( b , d ) (b,d) (b,d) 就对所有 a < l ≤ b , d ≤ r a<l\leq b,d\leq r a<l≤b,d≤r 的询问产生 1 的贡献、
时间复杂度 O ( n log 2 n ) O(n\log^2n) O(nlog2n) 。
CODE
#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<random>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#pragma GCC optimize(2)
using namespace std;
#define MAXN 100005
#define LL long long
#define ULL unsigned long long
#define UIN unsigned int
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define PR pair<int,int>
int xchar() {
static const int maxn = 1000000;
static char b[maxn];
static int pos = 0,len = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
//#define getchar() xchar()
LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}
const int MOD = 998244353;
int n,m,s,o,k;
int hd[MAXN],nx[MAXN<<1],v[MAXN<<1],w[MAXN<<1],cne;
void ins(int x,int y,int z) {
nx[++ cne] = hd[x]; v[cne] = y; hd[x] = cne; w[cne] = z;
}
LL d[MAXN];
set<int> st[MAXN];
map<LL,set<PR>> mp;
void merg(set<int>&a,set<int>&b,LL de) {
if(a.size() < b.size()) swap(a,b);
for(auto i = b.begin();i != b.end();i ++) {
auto j = a.lower_bound(*i);
if(j != a.end()) mp[de].insert({-(*i),*j});
if(j != a.begin()) mp[de].insert({-(*(--j)),*i});
}
for(auto i = b.begin();i != b.end();i ++) a.insert(*i);
b.clear();
}
void dfs(int x,int ff) {
st[x].insert(x); mp[d[x]].insert({-x,x});
for(int i = hd[x];i;i = nx[i]) {
if(v[i] != ff) {
d[v[i]] = d[x] + w[i];
dfs(v[i],x);
merg(st[x],st[v[i]],d[x]);
}
} return ;
}
vector<PR> bu[MAXN];
int qr[MAXN*5],as[MAXN*5];
vector<int> qu[MAXN];
int c[MAXN];
void addc(int x,int y) {while(x<=n)c[x]+=y,x+=lowbit(x);}
int sum(int x) {int s=0;while(x>0)s+=c[x],x&=(x-1);return s;}
int main() {
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n = read(); m = read();
for(int i = 1;i < n;i ++) {
s = read();o = read();k = read();
ins(s,o,k); ins(o,s,k);
}
dfs(1,0);
for(auto i = mp.begin();i != mp.end();i ++) {
auto &se = i->SE;
int mn = 0x3f3f3f3f;
for(auto j = se.begin();j != se.end();j ++) {
if(j->SE < mn) {
bu[-(j->FI)].push_back({j->SE,mn-1});
mn = j->SE;
}
}
}
for(int i = 1;i <= m;i ++) {
s = read(); qr[i] = read();
qu[s].push_back(i);
}
for(int i = n;i > 0;i --) {
for(auto &p:bu[i]) {
addc(p.FI,1); addc(p.SE+1,-1);
}
for(auto &x:qu[i]) {
as[x] = sum(qr[x]);
}
}
for(int i = 1;i <= m;i ++) {
AIput(as[i],'\n');
}
return 0;
}