SPOJ COT2

本文介绍了一种针对树状结构中节点间路径上的权重查询优化算法。通过预处理树结构和使用离线查询技巧,该算法能高效地解决查询路径上不同整数权重的数量问题。文章详细展示了算法实现步骤,并提供了完整的C++代码示例。

题目:

    

Description

 

You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight.

We will ask you to perfrom the following operation:

  • u v : ask for how many different integers that represent the weight of nodes there are on the path from u to v.

 

Input

In the first line there are two integers N and M.(N<=40000,M<=100000)

In the second line there are N integers.The ith integer denotes the weight of the ith node.

In the next N-1 lines,each line contains two integers u v,which describes an edge (u,v).

In the next M lines,each line contains two integers u v,which means an operation asking for how many different integers that represent the weight of nodes there are on the path from u to v.

Output

For each operation,print its result.

Example

Input:           
8 5
8 2 105 2 9 3 8 5 7 7 1 2 1 3 1 4 3 5 3 6 3 7 4 8
2 5
7 8
Output: 4

 

<p>You are given a tree with <strong>N</strong> nodes.The tree nodes are numbered from <strong>1</strong> to <strong>N</strong>.Each node has an integer weight.</p>
<p>We will ask you to perfrom the following operation:</p>
<ul>
<li><strong>u v k</strong> : ask for the kth minimum weight on the path from node <strong>u</strong> to node <strong>v</strong></li>
</ul>
<p> </p>
<h3>Input</h3>
<p>In the first line there are two integers <strong>N</strong> and <strong>M</strong>.(<strong>N,M</strong><=100000)</p>
<p>In the second line there are <strong>N</strong> integers.The ith integer denotes the weight of the ith node.</p>
<p>In the next <strong>N-1</strong> lines,each line contains two integers <strong>u</strong> <strong>v</strong>,which describes an edge (<strong>u</strong>,<strong>v</strong>).</p>
<p>In the next <strong>M</strong> lines,each line contains three integers <strong>u</strong> <strong>v</strong> <strong>k</strong>,which means an operation asking for the kth minimum weight on the path from node <strong>u</strong> to node <strong>v</strong>.</p>
<h3>Output</h3>
<p>For each operation,print its result.</p>
<h3>Example</h3>
<pre><strong>Input:</strong>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 320px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">8 5</div>8 5
105 2 9 3 8 5 7 7
1 2        
1 3
1 4
3 5
3 6
3 7
4 8<br />2 5 1<br />2 5 2<br />2 5 3<br />2 5 4<br />7 8 2 </pre>
<pre><strong>Output:</strong>
2<br />8<br />9<br />105<br />7 </pre>

 

 

 

网上大概看到两种解法,一种是:http://blog.youkuaiyun.com/kuribohg/article/details/41458639 

                                        用xor 思想求得

再一种就是这种直接求得:http://blog.youkuaiyun.com/u013598409/article/details/44943851 

我说第二种:

先ORZ 这位博主的代码 :

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <algorithm>
  6  using  namespace std;
  7 
  8  const  int N= 40001;
  9  const  int M= 161121;
 10  const  int K= 16;
 11 
 12  struct R
 13 {
 14      int d,id;
 15 }rk[N];
 16  int n,m,w[N];
 17  struct G
 18 {
 19      int v,nxt;
 20 }map[N<< 1];
 21  int tot,hd[N];
 22  int  in[N], out[N],lst[N<< 1],num;
 23  int pre[K+ 2][N],dep[N];
 24  struct Q
 25 {
 26      int l,r,anc,id;
 27 }q[M];
 28  int v[N],unit,res,l,r,has[N],ans[M];     // 注意ans的数据范围,为询问的个数
 29 
 30 inline  void ins( int u, int v)
 31 {
 32     map[++tot].v=v;
 33     map[tot].nxt=hd[u];
 34     hd[u]=tot;
 35 }
 36 
 37  void DFS( int now, int high)
 38 {
 39     dep[now]=high;
 40      in[now]=++num;
 41     lst[num]=now;
 42 
 43      for ( int k=hd[now];k;k=map[k].nxt)
 44          if (!dep[map[k].v])
 45         {
 46             DFS(map[k].v,high+ 1);
 47             pre[ 0][map[k].v]=now;
 48         }
 49 
 50      out[now]=++num;
 51     lst[num]=now;
 52 }
 53 
 54 inline  int cmp1(R a,R b)
 55 {
 56      return a.d<b.d;
 57 }
 58 
 59  void init( void)
 60 {
 61     scanf( " %d%d ",&n,&m);
 62      for ( int i= 1;i<=n;i++) scanf( " %d ",&w[i]);
 63 
 64      int tmp,cnt;
 65      for ( int i= 1;i<=n;i++) rk[i].d=w[i],rk[i].id=i;
 66     sort(rk+ 1,rk+n+ 1,cmp1);
 67     tmp=rk[ 1].d,w[rk[ 1].id]=cnt= 1;
 68      for ( int i= 2;i<=n;i++)
 69     {
 70          if (tmp^rk[i].d) tmp=rk[i].d,cnt++;
 71         w[rk[i].id]=cnt;
 72     }
 73 
 74      int x,y;
 75      for ( int i= 1;i<n;i++)
 76     {
 77         scanf( " %d%d ",&x,&y);
 78         ins(x,y),ins(y,x);
 79     }
 80 
 81     pre[ 0][ 1]= 1;
 82     DFS( 1, 1);
 83 
 84      for ( int i= 1;i<=K;i++)
 85          for ( int j= 1;j<=n;j++)
 86             pre[i][j]=pre[i- 1][pre[i- 1][j]];
 87 }
 88 
 89 inline  int cmp(Q a,Q b)
 90 {
 91      return a.l/unit!=b.l/unit?a.l/unit<b.l/unit:a.r<b.r;
 92 }
 93 
 94 inline  int min( int i, int j)
 95 {
 96      return i<j?i:j;
 97 }
 98 
 99 inline  int max( int i, int j)
100 {
101      return i>j?i:j;
102 }
103 
104 inline  int LCA( int x, int y)
105 {
106      if (dep[x]>dep[y]) x^=y^=x^=y;
107      for ( int i=K;i+ 1;i--)
108          if (dep[y]-dep[x]>= 1<<i) y=pre[i][y];
109      if (x==y)  return x;                             // 注意特判x=y时的LCA就是x=y
110       for ( int i=K;i+ 1;i--)
111          if (pre[i][x]^pre[i][y])
112             x=pre[i][x],y=pre[i][y];
113      return pre[ 0][x];
114 }
115 
116 inline  void solve( int i)         // "有无"时的写法
117  {
118      if (has[lst[i]])
119     {
120         v[w[lst[i]]]--;
121          if (!v[w[lst[i]]]) res--;
122         has[lst[i]]= 0;
123     }
124      else
125     {
126          if (!v[w[lst[i]]]) res++;
127         v[w[lst[i]]]++;
128         has[lst[i]]= 1;
129     }
130 }
131 
132  void work( void)
133 {
134      int x,y;
135     unit=( int)sqrt(num);             // num instead of n
136       for ( int i= 1;i<=m;i++)
137     {
138         scanf( " %d%d ",&x,&y);
139         q[i].id=i;
140          if (x==y) q[i].anc=- 1;
141          else
142         {
143             q[i].anc=LCA(x,y);
144              if (q[i].anc!=x&&q[i].anc!=y)
145             {
146                 q[i].l=min( out[x], out[y]);
147                 q[i].r=max( in[x], in[y]);
148             }
149              else
150             {
151                 q[i].l=min( in[x], in[y]);
152                 q[i].r=max( in[x], in[y]);
153             }                                 // (1)相同        (2)有1个为LCA:两个in    (3) 都不同:max(in)&&min(out)
154          }
155     }
156     sort(q+ 1,q+m+ 1,cmp);         // 注意用id弄到ans,不能直接输出
157 
158     l= 1,r= 0;
159      for ( int i= 1;i<=m;i++)
160          if (q[i].anc==- 1) ans[q[i].id]= 1;
161          else
162         {
163              for (;l<q[i].l;l++) solve(l);
164              for (;q[i].l<l;l--)    solve(l- 1);
165              for (;r<q[i].r;r++) solve(r+ 1);
166              for (;q[i].r<r;r--) solve(r);
167              if (lst[q[i].l]==q[i].anc||lst[q[i].r]==q[i].anc)     // 注意加上lst
168                  ans[q[i].id]=res;
169              else
170             {
171                 solve( in[q[i].anc]);
172                 ans[q[i].id]=res;
173                 solve( in[q[i].anc]);
174             }
175         }
176 
177      for ( int i= 1;i<=m;i++) printf( " %d\n ",ans[i]);
178 }
179 
180  int main( void)
181 {
182     init();
183     work();
184 
185      return  0;

186 } 

转载于:https://www.cnblogs.com/forgot93/p/4788311.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值