[扫描线][线段树]JZOJ 6276 树
分析
我们考虑把DFS序处理出来,然后显然,当两个不可互选的点不为祖先关系时,其不合法的路径条数有子树大小的乘积中
我们把这个抽象成二维平面,就是一个点的DFS序和子树中的最大DFS序作为宽,另一个类似作为长的矩形的面积
我们把所有点对都放到平面里,总面积就是不合法方案数,可以用扫描线+线段树处理
祖先关系也类似,只是祖先包含这个儿子的子树不能被选,所以是[1,l[son]-1][r[son]+1,n]的两个边界矩形
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N=1e5+10; struct Line { int x,l,r,c; }h[4*N]; int lcnt; struct Graph { int v,nx; }g[2*N]; int cnt,list[N],l[N],r[N],tme,f[N][20],dep[N],t[4*N],v[4*N]; int n,m; long long ans; void Add(int u,int v) { g[++cnt]=(Graph){v,list[u]};list[u]=cnt; g[++cnt]=(Graph){u,list[v]};list[v]=cnt; } void Addline(int x0,int x1,int y0,int y1) { h[++lcnt]=(Line){x0,y0,y1,1};h[++lcnt]=(Line){x1+1,y0,y1,-1}; } void DFS(int u,int fa) { f[u][0]=fa;l[u]=++tme;dep[u]=dep[fa]+1; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) DFS(g[i].v,u); r[u]=tme; } int LCA(int a,int b) { if (dep[a]<dep[b]) swap(a,b); for (int i=19;i>=0;i--) if (dep[f[a][i]]>=dep[b]) a=f[a][i]; if (a==b) return a; for (int i=19;i>=0;i--) if (f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i]; return f[a][0]; } bool CMP(Line a,Line b) { return a.x<b.x; } void Change(int x,int l,int r,int ll,int rr,int c) { if (r<l||rr<l||r<ll) return; if (ll<=l&&r<=rr) { t[x]+=c; if (t[x]) v[x]=r-l+1; else if (l!=r) v[x]=v[x<<1]+v[(x<<1)+1]; else v[x]=0; return; } int mid=l+r>>1; if (ll<=mid) Change(x<<1,l,mid,ll,rr,c); if (mid<rr) Change((x<<1)+1,mid+1,r,ll,rr,c); v[x]=t[x]?r-l+1:v[x<<1]+v[(x<<1)+1]; } int main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),Add(u,v); DFS(1,0); for (int i=1;i<20;i++) for (int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1]; for (int i=1,x,y;i<=m;i++) { scanf("%d%d",&x,&y); if (l[x]>l[y]) swap(x,y); int lca=LCA(x,y); if (lca==x) { int s=y; for (int i=19;i>=0;i--) if (dep[f[s][i]]>dep[x]) s=f[s][i]; if (l[s]-1>0) Addline(1,l[s]-1,l[y],r[y]); if (r[s]+1<=n) Addline(l[y],r[y],r[s]+1,n); } else Addline(l[x],r[x],l[y],r[y]); } sort(h+1,h+lcnt+1,CMP); for (int i=1,j=1;i<=n;i++) { while (h[j].x==i&&j<=lcnt) Change(1,1,n,h[j].l,h[j].r,h[j].c),j++; ans+=v[1]; } printf("%lld\n",1ll*n*(n-1ll)/2ll-ans); }
在日渐沉没的世界里,我发现了你。