码迷,mamicode.com
首页 > 其他好文 > 详细

[扫描线][倍增][dfs序][线段树] Jzoj P6276 树

时间:2019-08-07 22:49:02      阅读:93      评论:0      收藏:0      [点我收藏+]

标签:nbsp   set   names   节点   using   script   swa   mes   pen   

Description

有一棵n个节点的无根树,给出其中的m对点对<x,y>。问有多少条树上的简单路径<u,v>满足该路径上不存在任何一对给出的点对<x,y>。
这里我们认为路径<u,v>和<v,u>是相同的。并且对于题目中给出的点对<x,y>满足x!=y,对于你要计数的路径<u,v>满足u!=v(即单点不算答案)。

 

题解

  • 我们先把每个点在dfs上入队出队的时间给弄出来
  • 然后可以转换为在平面上的n个矩阵
  • 就可以用扫描线+线段树给过掉它了

 

代码

 1 #include <cstdio>
 2 #include <algorithm>
 3 #define N 100010
 4 #define ll long long
 5 using namespace std;
 6 struct edge { ll to,from; }e[N*2];
 7 struct Edge{ ll l,r,x,k; }a[N*40];
 8 ll n,m,tot,cnt,num,ans,p=1,fa[17][N],head[N],d[N*4],tag[N*4],dfn[N][2],t[N*4];
 9 bool cmp(Edge a,Edge b) { return a.x<b.x; }
10 void insert(ll x,ll y) 
11 { 
12     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt;
13     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt;
14 }
15 void ins(ll x1,ll x2,ll y1,ll y2) { a[++num]=(Edge){x1,x2,y1,1},a[++num]=(Edge){x1,x2,y2+1,-1}; }
16 void dfs(ll x)
17 {
18     dfn[x][0]=++tot;
19     for (ll i=head[x];i;i=e[i].from) if (!dfn[e[i].to][0]) dfs(e[i].to),fa[0][e[i].to]=x;
20     dfn[x][1]=tot;
21 }
22 void add(ll d,ll l,ll r,ll L,ll R,ll x)
23 {
24     if (l==L&&r==R)
25     {
26         tag[d]+=x;
27         if (l==r) t[d]=(tag[d]>0); else if (tag[d]) t[d]=r-l+1; else t[d]=t[d*2]+t[d*2+1];
28         return;
29     }
30     ll mid=l+r>>1;
31     if (R<=mid) add(d*2,l,mid,L,R,x); else if (L>mid) add(d*2+1,mid+1,r,L,R,x);
32     else add(d*2,l,mid,L,mid,x),add(d*2+1,mid+1,r,mid+1,R,x);
33     if (tag[d]) t[d]=r-l+1; else t[d]=t[d*2]+t[d*2+1];
34 }
35 int main()
36 {
37     freopen("tree.in","r",stdin),freopen("tree.out","w",stdout),scanf("%lld%lld",&n,&m);
38     for (ll i=1,x,y;i<n;i++) scanf("%lld%lld",&x,&y),insert(x,y);
39     dfs(1);
40     for (ll i=1;i<=16;i++) for (ll j=1;j<=n;j++) fa[i][j]=fa[i-1][fa[i-1][j]];
41     for (ll i=1,x,y,x1,y1,x2,y2;i<=m;i++)
42     {
43         scanf("%lld%lld",&x,&y),x1=dfn[x][0],y1=dfn[y][0],x2=dfn[x][1],y2=dfn[y][1];
44         if (x1>y1) swap(x,y),swap(x1,y1),swap(x2,y2);
45         if (x2<y1) ins(x1,x2,y1,y2),ins(y1,y2,x1,x2);
46         else 
47         {
48             ll p=y;
49             for (ll j=16;j>=0;j--) if (dfn[fa[j][p]][0]>x1) p=fa[j][p];
50             if (dfn[p][0]>1) ins(1,dfn[p][0]-1,y1,y2),ins(y1,y2,1,dfn[p][0]-1);
51             if (dfn[p][1]!=n) ins(dfn[p][1]+1,n,y1,y2),ins(y1,y2,dfn[p][1]+1,n);
52         }
53     }
54     sort(a+1,a+num+1,cmp);
55     for (ll i=1;i<=n;i++)
56     {
57         while (p<=num&&a[p].x==i) { add(1,1,n,a[p].l,a[p].r,a[p].k),p++; }
58         ans+=t[1];
59     }
60     ans=(n*(n-1)-ans)/2,printf("%lld",ans);
61 }

 

[扫描线][倍增][dfs序][线段树] Jzoj P6276 树

标签:nbsp   set   names   节点   using   script   swa   mes   pen   

原文地址:https://www.cnblogs.com/Comfortable/p/11318037.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!