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

【NOIP2017 by Anson】天哥种树

时间:2017-10-29 13:48:07      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:max   没有   min   noi   reg   技巧   sort   int   cst   

【问题描述】
  
年少时,qt666曾在花园内种下了一棵树。如今,树长大了,n个节点上都各自结出了一个果子。其中,有20个奇妙的果子,它们权值分别为20~219。其它的果子的权值都是0。淘气的果子们常常会互相交换位置。作为一位勤思好问的新时代好少年,qt666想知道:对于树上的两个点x,y,两点间路径的子路径中有多少条满足路径上的果子的权值的异或和为k?
【输入】
第一行为n和m,分别为树上节点数以及操作个数。
接下来n-1行,每行2个整数x,y,表示节点之间有一条边。
接下来一行包含20个整数,分别表示权值为20~219的果子的初始位置。
接下来m行,每行现有一个整数op,其中:
op==0:输入x,y,交换的果子的初始位置。
op==1:输入x,y,k,表示一组询问,意义如问题描述所述。
【输出】
对于每个op==1,输出一行一个整数表示符合要求的路径数。
【样例输入】

20 20
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
19 11 9 12 5 17 6 1 2 18 15 8 16 10 3 4 20 13 14 7
0 6 17
0 7 7
0 20 20
0 13 11
1 11 2 715060
0 13 13
1 16 2 982334
0 18 19
1 17 15 5184
0 18 9
1 14 15 263168
1 19 13 267846
1 15 4 961595
0 6 16
0 1 19
1 3 11 718865
0 12 6
1 6 15 932875
1 2 3 16640
0 8 20

【样例输出】

1
1
1
1
1
1
1
1
1

【数据范围】
前40%:n,m≤100
另外16%:n,m≤5000
另外16%:k==0
前80%:n,m≤100000
前100%:n,m≤500000,20≤n,k<220

 题解:

  只有20个数,而且这20个数的二进制位上只有一个1。0异或任何数都不变,那么可以直接考虑这20个树。

  我们把一条路径看成一个序列,每一次枚举0~19,如果k&(1<<i)==1但是没有出现在这一个序列之中,就显然答案为0。如果全部出现了,那么记l,r代表正好l,r的这一段区间之内的数异或和为k,也就是再减少一个就不是k了。然后每次抠出一个序列,然后就直接计算即可,记下所有有值但不是所需的,合法区间必须在两个相邻的值之间,但是如果k=0,特判即可。

  技巧:判断一个点是不是在子树中,可以根据dfn1和dfn2来判断,要判断是否在一个路径上,就先判断子树,然后判断起点在不在他的子树中。

  1 #include<queue>
  2 #include<cstdio>
  3 #include<vector>
  4 #include<cstring>
  5 #include<iostream>
  6 #include<algorithm>
  7 #define RG register
  8 #define LL long long
  9 #define fre(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
 10 using namespace std;
 11 const int MAXN=510000;
 12 int n,m,num,tp,DFN;
 13 int fa[MAXN][20],dep[MAXN],head[MAXN],to[MAXN*2],Next[MAXN*2];
 14 int w[MAXN],st[MAXN],A[MAXN],dfn1[MAXN],dfn2[MAXN];
 15 LL ans;
 16 void add(int f,int t)
 17 {
 18    Next[++num]=head[f];
 19    to[num]=t;
 20    head[f]=num;
 21 }
 22 void dfs(int u,int FA)
 23 {
 24    dfn1[u]=++DFN;
 25    for(int i=head[u];i;i=Next[i])
 26       {
 27          int v=to[i];
 28          if(v==FA)continue;
 29          fa[v][0]=u;
 30          dep[v]=dep[u]+1;
 31          dfs(v,u);
 32       }
 33    dfn2[u]=DFN;
 34 }
 35 int LCA(int x,int y)
 36 {
 37    if(dep[x]<dep[y])swap(x,y);
 38    int cha=dep[x]-dep[y];
 39    for(int i=0;i<20;i++)
 40       if(cha&(1<<i))x=fa[x][i];
 41    if(x==y)return x;
 42    for(int j=19;j>=0;j--)
 43       if(fa[x][j]!=fa[y][j])
 44          x=fa[x][j],y=fa[y][j];
 45    return fa[x][0];
 46 }
 47 bool cal(int x,int y)
 48 {
 49    return dfn1[x]<=dfn1[y]&&dfn1[y]<=dfn2[x];
 50 }
 51 int main()
 52 {
 53    scanf("%d%d",&n,&m);
 54    for(int i=1,a,b;i<n;i++)
 55       {
 56          scanf("%d%d",&a,&b);
 57          add(a,b); add(b,a); w[i]=20;
 58       }w[n]=20;
 59    dfs(1,0);
 60    for(int j=1;j<20;j++)
 61       for(int i=1;i<=n;i++)
 62          fa[i][j]=fa[fa[i][j-1]][j-1];
 63    for(int i=0;i<20;i++)
 64       {
 65          scanf("%d",&A[i]);
 66          w[A[i]]=i;
 67       }
 68    while(m--)
 69       {
 70          RG int op,x,y,k;
 71          scanf("%d",&op);
 72          if(op==0)
 73             {
 74                scanf("%d%d",&x,&y);
 75                A[w[x]]=y; A[w[y]]=x;
 76                swap(w[x],w[y]);
 77             }
 78          else if(op==1)
 79             {
 80                scanf("%d%d%d",&x,&y,&k); ans=0; tp=0;
 81                RG int lca=LCA(x,y),len=dep[x]+dep[y]-2*dep[lca],l=len,r=0,flag=0;
 82                for(RG int i=0,c,p;i<20;i++)
 83                   {
 84                      p=A[i]; c=-1;
 85                      if(cal(lca,p))
 86                         {
 87                            if(cal(p,x)) c=dep[x]-dep[p];
 88                            if(cal(p,y)) c=dep[x]+dep[p]-2*dep[lca];
 89                         }
 90                      if(c==-1) { if(k&(1<<i)){ flag=1; break; } }
 91                      else
 92                         {
 93                            if(k&(1<<i)) l=min(l,c),r=max(r,c);
 94                            else st[++tp]=c;
 95                         }
 96                   }
 97                if(flag) { printf("0\n"); continue; }
 98                sort(st+1,st+tp+1);
 99                st[0]=-1; st[++tp]=len+1;
100                if(k==0)
101                   for(int i=1,h;i<=tp;i++)
102                      {
103                         h=st[i]-st[i-1]-1;
104                         ans+=(LL)(h+1)*h/2;
105                      }
106                else
107                   for(int i=1;i<=tp;i++)
108                      if(st[i-1]<l && r<st[i])
109                         ans+=(LL)(l-st[i-1])*(st[i]-r);
110                printf("%lld\n",ans);
111             }
112       }
113    return 0;
114 }

【NOIP2017 by Anson】天哥种树

标签:max   没有   min   noi   reg   技巧   sort   int   cst   

原文地址:http://www.cnblogs.com/D-O-Time/p/7749846.html

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