[拒绝毒瘤的小清新系列] give you a tree
(小声)这其实是我读错某题之后自己出的一道题。。。。。。
正解也很简单啦,直接扫描线+线段树水过(考虑一个合法的区间正好有 siz-1 对树上相邻的点对)23333
#include<cstdio> #include<vector> #define ll long long using namespace std; const int N=300005; #define pb push_back #define lc (o<<1) #define mid (l+r>>1) #define rc ((o<<1)|1) vector<int> g[N]; int mx[N*4],sum[N*4],tag[N*4],le,ri,w,n; ll ans=0; inline void maintain(int o){ mx[o]=max(mx[lc],mx[rc]); sum[o]=(mx[lc]==mx[o]?sum[lc]:0)+(mx[rc]==mx[o]?sum[rc]:0); } inline void work(int o,int der){ tag[o]+=der,mx[o]+=der;} inline void pushdown(int o){ if(tag[o]){ work(lc,tag[o]),work(rc,tag[o]); tag[o]=0; } } void ud1(int o,int l,int r){ if(l>=le&&r<=ri){ work(o,w); return;} pushdown(o); if(le<=mid) ud1(lc,l,mid); if(ri>mid) ud1(rc,mid+1,r); maintain(o); } void ud2(int o,int l,int r){ if(l==r){ sum[o]=1,mx[o]=l; return;} pushdown(o); if(le<=mid) ud2(lc,l,mid); else ud2(rc,mid+1,r); maintain(o); } inline void solve(){ for(int i=1;i<=n;i++){ le=i,ud2(1,1,n),le=w=1; for(int j:g[i]) ri=j,ud1(1,1,n); ans+=(ll)sum[1]; } } int main(){ scanf("%d",&n); int uu,vv; for(int i=1;i<n;i++){ scanf("%d%d",&uu,&vv); if(uu>vv) swap(uu,vv); g[vv].pb(uu); } solve(); printf("%lld\n",ans); return 0; }
我爱学习,学习使我快乐