HDU4812 D Tree(树的点分治)

题目大概说给一棵有点权的树,输出字典序最小的点对,使这两点间路径上点权的乘积模1000003的结果为k。

树的点分治搞了。因为是点权过根的两条路径的LCA会被重复统计,而注意到1000003是质数,所以这个用乘法逆元搞一下就OK了。还有要注意“治”的各个实现,把时间复杂度“控制”在O(nlogn)。

WA了几次,WA在漏了点到子树根的路径,还有每次分治忘了清空数组。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 #define INF (1<<30)
  6 #define MAXN 111111
  7 struct Edge{
  8     int v,next;
  9 }edge[MAXN<<1];
 10 int NE,head[MAXN];
 11 void addEdge(int u,int v){
 12     edge[NE].v=v; edge[NE].next=head[u]; head[u]=NE++;
 13 }
 14 bool vis[MAXN];
 15 int mini,cen,size[MAXN];
 16 void getSize(int u,int fa){
 17     size[u]=1;
 18     for(int i=head[u]; i!=-1; i=edge[i].next){
 19         int v=edge[i].v;
 20         if(v==fa || vis[v]) continue;
 21         getSize(v,u);
 22         size[u]+=size[v];
 23     }
 24 }
 25 void getCen(int u,int fa,int &tot){
 26     int res=tot-size[u];
 27     for(int i=head[u]; i!=-1; i=edge[i].next){
 28         int v=edge[i].v;
 29         if(v==fa || vis[v]) continue;
 30         getCen(v,u,tot);
 31         res=max(res,size[v]);
 32     }
 33     if(res<mini) mini=res,cen=u;
 34 }
 35 int getCen(int u){
 36     getSize(u,u);
 37     mini=INF;
 38     getCen(u,u,size[u]);
 39     return cen;
 40 }
 41 long long ine(long long a){
 42     long long res=1,n=1000001;
 43     while(n){
 44         if(n&1) res*=a,res%=1000003;
 45         a*=a; a%=1000003;
 46         n>>=1;
 47     }
 48     return res;
 49 }
 50 int n,k,val[MAXN];
 51 int ansx,ansy;
 52 int record[1000003],tn,tmpx[MAXN],tmpy[MAXN],all[MAXN],an;
 53 void dfs(int u,int fa,long long dist,int &top){
 54     int v=record[ine(dist)*k%1000003*top%1000003];
 55     if(v){
 56         if(u<v){
 57             if(u<ansx) ansx=u,ansy=v;
 58             else if(u==ansx && v<ansy) ansy=u,ansy=v;
 59         }else{
 60             if(v<ansx) ansx=v,ansy=u;
 61             else if(v==ansx && u<ansy) ansy=v,ansy=u;
 62         }
 63     }
 64     tmpx[tn]=u; tmpy[tn]=dist; ++tn;
 65     all[an++]=dist;
 66     for(int i=head[u]; i!=-1; i=edge[i].next){
 67         int v=edge[i].v;
 68         if(v==fa || vis[v]) continue;
 69         dfs(v,u,dist*val[v]%1000003,top);
 70     }
 71 }
 72 void conquer(int u){
 73     an=0;
 74     all[an++]=val[u];
 75     record[val[u]]=u;
 76     for(int i=head[u]; i!=-1; i=edge[i].next){
 77         int v=edge[i].v;
 78         if(vis[v]) continue;
 79         tn=0;
 80         dfs(v,v,(long long)val[u]*val[v]%1000003,val[u]);
 81         for(int j=0; j<tn; ++j){
 82             if(record[tmpy[j]]==0 || record[tmpy[j]]>tmpx[j]) record[tmpy[j]]=tmpx[j];
 83         }
 84     }
 85     for(int i=0; i<an; ++i) record[all[i]]=0;
 86 }
 87 void divide(int u){
 88     u=getCen(u);
 89     vis[u]=1;
 90     conquer(u);
 91     for(int i=head[u]; i!=-1; i=edge[i].next){
 92         int v=edge[i].v;
 93         if(vis[v]) continue;
 94         divide(v);
 95     }
 96 }
 97 int main(){
 98     int a,b;
 99     while(~scanf("%d%d",&n,&k)){
100         for(int i=1; i<=n; ++i){
101             scanf("%d",val+i);
102         }
103         NE=0;
104         memset(head,-1,sizeof(head));
105         for(int i=1; i<n; ++i){
106             scanf("%d%d",&a,&b);
107             addEdge(a,b);
108             addEdge(b,a);
109         }
110         memset(vis,0,sizeof(vis));
111         ansx=ansy=INF;
112         divide(1);
113         if(ansx==INF) puts("No solution");
114         else printf("%d %d\n",ansx,ansy);
115     }
116     return 0;
117 }
时间: 2024-10-12 14:34:01

HDU4812 D Tree(树的点分治)的相关文章

hdu 4812 D Tree(树的点分治)

D Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 1687    Accepted Submission(s): 263 Problem Description There is a skyscraping tree standing on the playground of Nanjing University of

POJ 1741 Tree(树的点分治,入门题)

Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21357   Accepted: 7006 Description Give a tree with n vertices,each edge has a length(positive integer less than 1001).Define dist(u,v)=The min distance between node u and v.Give an in

【POJ 1741】 Tree (树的点分治)

Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v)

HDU 4670 Cube number on a tree ( 树的点分治 )

题意 : 给你一棵树 . 树的每一个结点都有一个权值 . 问你有多少条路径权值的乘积是一个全然立方数 . 题目中给了你 K 个素数 ( K <= 30 ) , 全部权值都能分解成这k个素数 思路 : 一个全然立方数的素因子个数都是三的倍数 , 所以我们仅仅要求各个素数的个数即可了 , 而且我们仅仅关心个数对三的余数 所以我们能够用一个 长整形来表示每一个结点到根的各个素因子的个数( 三进制压缩 ) . 只是由于用位运算会快一点 , 所以我用了四进制.即每两位表示一个素因子的个数 . 中间合并的时

POJ 1741 Tree 树的点分治

题目大意:给定一棵树,求树上距离不超过k的点对(x,y) (x<y)的数量 男人八题第五题...其实没那么难的说...比NOI2014最后一题好写多了0.0 首先两个点之间的路径有两种情况: 1.两点之间路径经过根 2.两点之间路径不经过根 首先讨论情况1 我们从根出发进行一次DFS,求出每个点到根的距离,排序,然后扫一遍数组O(n)出解 但其中如果两个点都属于根的同一棵子树,那么这两个点的路径一定是不经过根的,我们还要把这些点对减掉 于是枚举子树,同样把距离排序,扫数组即可 然后讨论情况2 既

POJ 1741 Tree 树+点分治

树的点分治 可以看09年漆子超论文,说的很详细. Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 12650   Accepted: 4025 Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance betwe

poj 1741 Tree(树的点分治)

poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出来.接着对于每一个子树再次运算.如果不用点分治的技巧,时间复杂度可能退化成\(O(n^2)\)(链).如果对于子树重新选根,找到树的重心,就一定可以保证时间复杂度在\(O(nlogn)\)内. 具体技巧是:首先选出树的重心,将重心视为根.接着计算出每个结点的深度,以此统计答案.由于子树中可能出现重复

POJ 1741 Tree 树的分治(点分治)

题目大意:给出一颗无根树和每条边的权值,求出树上两个点之间距离<=k的点的对数. 思路:树的点分治.利用递归和求树的重心来解决这类问题.因为满足题意的点对一共只有两种: 1.在以该节点的子树中且不经过该节点. 2.路径经过该节点. 对于第一种点,我们递归处理:第二种点,我们可以将所有子树的节点到这个子树的根节点的距离处理出来,然后排序处理出满足要求的点对的个数. 按照正常的树的结构来分割子树,这样的做法的时间复杂度肯定是不好看的,为了让子树大小尽量相同,我们每次处理这个子树前找到这个子树的重心,

POJ 1741 Tree DP+树的点分治

题意:链接 方法:树的点分治+DP 解析: 男八之一 听完封禺讲完来刷 然后发现有些地方是需要注意的! 首先先说这个树 树上的所有点分为两类 一类是两个点间不经过根节点,另一类是经过根节点 这里不经过根节点的显然递归求解即可 我们只需要O(n)扫一下所有点到根节点的距离,然后用神♂奇的双指针判断一下有多少对就可以了,但是这样的话有可能有两个点在同一个根节点的子节点为根节点的子树里,也就是说这样的话我们会算多一部分,只需要减掉子节点的计算就可以了. 代码: #include <cstdio> #