codeforces 293E 树上点分治+bit维护二维偏序
https://codeforc.es/contest/293/problem/E
题解:
如果我们和poj1741一样,暴力预处理出子树中所有的点对信息
那么问题就变成了一个二维偏序问题
多少个点对满足w1+w2<=W且l1+l2<=L
参考树状数组求逆序对,用树状数组保存l1的信息,对于每个l2,查询前缀和,然后删除自身
注意细节
#include<bits/stdc++.h> #define endl '\n' #define ll long long #define ull unsigned long long #define fi first #define se second #define mp make_pair #define pii pair<ll,int> #define all(x) x.begin(),x.end() #define IO ios::sync_with_stdio(false) #define show(x) cout<<#x<<"="<<x<<endl #define show2(x,y) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl #define show3(x,y,z) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define show4(w,x,y,z) cout<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define show5(v,w,x,y,z) cout<<#v<<"="<<v<<" "<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define showa(a,b) cout<<#a<<'['<<b<<"]="<<a[b]<<endl #define rep(ii,a,b) for(int ii=a;ii<=b;++ii) #define per(ii,a,b) for(int ii=b;ii>=a;--ii) #define forn(i,x) for(int i=head[x];i;i=e[i].next) using namespace std; const int maxn=1e5+10,maxm=2e5+10; const int INF=0x3f3f3f3f; const int mod=1e9+7; const double PI=acos(-1.0); int casn,n,m; ll k; struct bit{ ll node[maxn]; inline int lb(int x) {return x&(-x);} inline void update(int pos,ll val=1){ pos++;if(pos<=0) return ; for(int i=pos;i&&i<=n;i+=lb(i))node[i]+=val; } inline ll ask(int pos){ ll sum=0;pos++;if(pos<=0) return 0; for(int i=pos;i>0;i-=lb(i))sum+=node[i];return sum; } inline ll query(int l,int r){return ask(r)-ask(l-1);} }tree; class graph{public: struct node{int to,next;ll cost;}e[maxm]; int head[maxn],nume,n,sz[maxn],maxt,stree[maxn]; void add(int a,int b,ll c=0){e[++nume]={b,head[a],c};head[a]=nume;} int vis[maxn],num[maxn],all,mid; void getmid(int now=1,int pre=0){ sz[now]=1; for(int i=head[now];i;i=e[i].next){ if(e[i].to==pre||vis[e[i].to]) continue; getmid(e[i].to,now); sz[now]+=sz[e[i].to]; } int tmp=max(sz[now]-1,all-sz[now]); if(maxt>tmp) maxt=tmp,mid=now; }//base pii dis[maxn]; int dfn,mxd; ll ans; void init(int n){ this->n=n,nume=1,mid=0; rep(i,1,n) vis[i]=head[i]=0; } ll getdis(int now,int pre,int d,ll s){ dis[++dfn]={s,d};mxd=max(mxd,d); for(int i=head[now];i;i=e[i].next){ int to=e[i].to; if(to==pre||vis[to]) continue; getdis(to,now,d+1,s+e[i].cost); } } ll getans(int now,int d=0,ll s=0){ dfn=0;mxd=0; getdis(now,0,d,s); sort(dis+1,dis+1+dfn); ll ans=0; int l=1,r=dfn; while(l<r&&dis[l].fi+dis[r].fi>k)r--; rep(i,l+1,r) tree.update(dis[i].se); while(l<r){ if(dis[l].fi+dis[r].fi<=k) { ans+=tree.ask(min(m-dis[l].se,mxd)); tree.update(dis[++l].se,-1); }else tree.update(dis[r--].se,-1); } return ans; } void divide(int now){ vis[now]=1;ans+=getans(now); for(int i=head[now];i;i=e[i].next){ int to=e[i].to; if(vis[to]) continue; ans-=getans(to,1,e[i].cost); all=sz[to],maxt=n+1; getmid(to,now);divide(mid); } } void solve(){ ans=0;maxt=all=n; getmid();divide(mid); } }g; int main() {IO; cin>>n>>m>>k; g.init(n); rep(i,2,n){ int a;ll c;cin>>a>>c; g.add(i,a,c);g.add(a,i,c); } g.solve(); cout<<g.ans<<endl; }