博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SPOJ - COT2 Count on a tree II
阅读量:5057 次
发布时间:2019-06-12

本文共 4457 字,大约阅读时间需要 14 分钟。

Discription

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 perform 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 i-th integer denotes the weight of the i-th node.

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

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 2105 2 9 3 8 5 7 71 21 31 43 53 63 74 82 57 8
Output:44     原来不仅子树询问可以树上莫队啊,路径询问也可以!  (树上莫队板子题)     对于路径询问,我们对于每个点x要记录两个dfs_clock,一个是进入这个点的(设为B[x]),一个是出这个点的(设为E[x])。     接下来按照询问点(u,v)分类讨论(假设 B[u] < B[v]):           1.u是v的祖先:这种情况下直接询问dfs序区间 [B[u],B[v]] ,只有在(u,v)路径上的点在其中恰好出现1次,其他的点要么没出现要么出现2次,可以直接判出来。         2.u,v无直接祖先关系:这种情况下需要询问 [E[u],B[v]] ,仍然满足上一种情况的性质(LCA除外,LCA在这种计算方式下会被算到0次,所以要最后加上),所以类似处理。         所以把询问放到dfs序上直接莫队就好了。     这里再补充一些我yy出来的这种计算dfs序方法的一些性质:         1.对于每个点x,[B[x],E[x]]构成了这颗子树的dfs序区间,所有该子树中的点在其中出现2次,其他点在其中出现0次;         2.对于任意两个点 x,y , [B[x],E[x]] 与 [B[y],E[y]] 要么是包含关系,要么是相离关系,并且是包含当且仅当x,y其中一个是另一个的祖先。         3.(上述莫队有关的性质)         4.(欢迎补充)       由于近期要准备NOI啦,所以代码的正确率非常重要,于是现在每次提交之前尽量都要自己写个暴力写个数据生成器拍一下啦(希望能坚持好习惯23333)。 (顺便贴一下暴力和数据生成代码吧2333) 暴力:
#include
#define ll long longusing namespace std;#define pb push_backconst int maxn=40005;vector
g[maxn];int n,m,a[maxn],num[maxn],ky;int dep[maxn],f[maxn],dc,c[maxn];void dfs(int x,int fa){ f[x]=fa; for(int i=g[x].size()-1,to;i>=0;i--){ to=g[x][i]; if(to!=fa) dep[to]=dep[x]+1,dfs(to,x); }}inline int calc(int x,int y){ int an=0; dc++; while(x!=y){ if(dep[x]>dep[y]){ if(c[a[x]]!=dc) c[a[x]]=dc,an++; x=f[x]; } else{ if(c[a[y]]!=dc) c[a[y]]=dc,an++; y=f[y]; } } return an+(c[a[x]]!=dc);}inline void solve(){ int uu,vv; for(int i=1;i<=m;i++){ scanf("%d%d",&uu,&vv); printf("%d\n",calc(uu,vv)); }}int main(){ freopen("data.in","r",stdin); freopen("ans.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",a+i),num[i]=a[i]; sort(num+1,num+n+1); int ky=unique(num+1,num+n+1)-num-1; for(int i=1;i<=n;i++) a[i]=lower_bound(num+1,num+ky+1,a[i])-num; int uu,vv; for(int i=1;i

  数据生成器(虽然直接随机挂父亲的树深是期望log的,,,但是反正正解和树深也没啥关系):

#include
#define ll long longusing namespace std;int main(){ freopen("data.in","w",stdout); srand(time(0)); int n=40000,m=100000; cout<
<<' '<
<

  

正解:
#include
#define ll long longusing namespace std;#define pb push_backconst int maxn=80005;vector
g[maxn];struct node{ int L,R,bl,num,A; bool operator <(const node &u)const{ return bl==u.bl?((bl&1)?R
u.R):bl
=0;i--){ to=g[x][i]; if(to!=fa) dep[to]=dep[x]+1,dfs(to,x); } dy[++dc]=x,E[x]=dc;}inline int LCA(int x,int y){ if(dep[x]
=0;i--) if(ci[i]<=dep[x]&&f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0];}inline void Get(int L,int R){ while(l>L){ l--; if(!p[dy[l]]){ p[dy[l]]=1; if(cnt[a[dy[l]]]==0) now++; cnt[a[dy[l]]]++; } else{ p[dy[l]]=0; cnt[a[dy[l]]]--; if(cnt[a[dy[l]]]==0) now--; } } while(r
R){ if(!p[dy[r]]){ p[dy[r]]=1; if(cnt[a[dy[r]]]==0) now++; cnt[a[dy[r]]]++; } else{ p[dy[r]]=0; cnt[a[dy[r]]]--; if(cnt[a[dy[r]]]==0) now--; } r--; } }inline void solve(){ int uu,vv; for(int i=1;i<=m;i++){ scanf("%d%d",&uu,&vv); if(B[uu]>B[vv]) swap(uu,vv); if(E[uu]>E[vv]) q[i]=(node){B[uu],B[vv],(B[uu]-1)/sz+1,i,0}; else q[i]=(node){E[uu],B[vv],(E[uu]-1)/sz+1,i,LCA(uu,vv)}; } sort(q+1,q+m+1),l=1,r=0; for(int i=1;i<=m;i++){ Get(q[i].L,q[i].R); ans[q[i].num]=now+(q[i].A&&!cnt[a[q[i].A]]); }}int main(){// freopen("data.in","r",stdin);// freopen("data.out","w",stdout); ci[0]=1; for(int i=1;i<=20;i++) ci[i]=ci[i-1]<<1; scanf("%d%d",&n,&m),sz=sqrt(n<<1); for(int i=1;i<=n;i++) scanf("%d",a+i),num[i]=a[i]; sort(num+1,num+n+1); int ky=unique(num+1,num+n+1)-num-1; for(int i=1;i<=n;i++) a[i]=lower_bound(num+1,num+ky+1,a[i])-num; int uu,vv; for(int i=1;i

  

 

转载于:https://www.cnblogs.com/JYYHH/p/9068306.html

你可能感兴趣的文章
复习文件操作
查看>>
C#Hashtable与Dictionary性能
查看>>
10个让你忘记 Flash 的 HTML5 应用演示
查看>>
8个Python面试必考的题目,小编也被坑过 ToT
查看>>
SQL Server 使用作业设置定时任务之一(转载)
查看>>
centos 图形界面和命令行界面切换(转载)
查看>>
Maven启用代理访问
查看>>
Primary definition
查看>>
第二阶段冲刺-01
查看>>
BZOJ1045 HAOI2008 糖果传递
查看>>
发送请求时params和data的区别
查看>>
JavaScript 克隆数组
查看>>
eggs
查看>>
一步步学习微软InfoPath2010和SP2010--第七章节--从SP列表和业务数据连接接收数据(4)--外部项目选取器和业务数据连接...
查看>>
如何增强你的SharePoint 团队网站首页
查看>>
FZU 1914 Funny Positive Sequence(线性算法)
查看>>
oracle 报错ORA-12514: TNS:listener does not currently know of service requested in connec
查看>>
基于grunt构建的前端集成开发环境
查看>>
MySQL服务读取参数文件my.cnf的规律研究探索
查看>>
java string(转)
查看>>