poj1741+poj1987+poj2114——点分治入门题集合

最近看了看点分治,从poj上找到几道题,都比较裸。而且感觉这三道题都长得差不多呀qwq

————————————————————————————————————————————————

【poj 1741】Tree

题意:给定一棵边带权的树,求两点之间的距离小于或等于K的点对个数。

找重心,相当于把无根树转变为有根树。再利用分治的思想(根据经过重心或不经过重心来划分)。

对于在同一个子树的情况要单独拎出来算并减去它们(因为是不该算在内的呀qwq)

另外选取重心的好处是时间复杂度O(NlogN*logN),如果选取其他的点,不能保证会不会退化到O(N2*logN)

//特别鸣谢,经@神犇gxz提醒,已改正刚才写时间复杂度的错误(大佬blog地址: http://www.cnblogs.com/GXZlegend/

  1 #include<cmath>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 const int maxn=10010;
  6 using namespace std;
  7 struct  Edge
  8 {
  9     int nxt;
 10     int to;
 11     int w;
 12     Edge(){}
 13     Edge(int _to,int _nxt,int _w):to(_to),nxt(_nxt),w(_w){}
 14 }edge[maxn<<1];
 15 int head[maxn],tot;
 16 void init()
 17 {
 18     memset(head,-1,sizeof(head));
 19     tot=0;
 20 }
 21
 22 void AddEdge(int u,int v,int w)
 23 {
 24
 25     edge[tot]=Edge(v,head[u],w);
 26     head[u]=tot++;
 27     edge[tot]=Edge(u,head[v],w);
 28     head[v]=tot++;
 29 }
 30
 31 int son[maxn],siz[maxn],has[maxn],root;
 32 int n,K;
 33 void getroot(int u,int fa)
 34 {
 35     siz[u]=1;son[u]=0;
 36     for(int i=head[u];i!=-1;i=edge[i].nxt)
 37     {
 38         int v = edge[i].to;
 39         if(has[v]||v == fa) continue;
 40         getroot(v,u);
 41         siz[u] += siz[v];
 42         son[u] = max(son[u],siz[v]);
 43     }
 44     son[u] = max(son[u],son[0]-siz[u]);
 45     if(son[u]<son[root]) root=u;
 46 }
 47 int dis[maxn],res[maxn];
 48 void getdis(int u,int fa)
 49 {
 50     res[++res[0]]=dis[u];
 51     siz[u]=1;
 52     for(int i=head[u];i!=-1;i=edge[i].nxt)
 53     {
 54         int v=edge[i].to;
 55         if(has[v]||v==fa) continue;
 56         dis[v]=dis[u]+edge[i].w;
 57         getdis(v,u);
 58         siz[u]+=siz[v];
 59     }
 60 }
 61 int calc(int u,int init)//计算ans
 62 {
 63     dis[u]=init;res[0]=0;getdis(u,u);
 64     sort(res+1,res+1+res[0]);
 65     int l=1,r=res[0];
 66     int ans=0;
 67     while(l<r)
 68     {
 69         if(res[l]+res[r]<=K)
 70             ans+=r-l++;
 71         else
 72             --r;
 73     }
 74     return ans;
 75 }
 76 int Ans;
 77 void dfs(int u)
 78 {
 79     Ans+=calc(u,0);
 80     has[u]=1;
 81     for(int i=head[u];i!=-1;i=edge[i].nxt)
 82     {
 83         int v=edge[i].to;
 84         if(has[v]) continue;
 85         Ans-=calc(v,edge[i].w);
 86         root=0;son[0]=siz[v];
 87         getroot(v,v);
 88         dfs(root);
 89     }
 90 }
 91 int main()
 92 {
 93     while(~scanf("%d%d",&n,&K))
 94     {
 95         int u,v,l;
 96         if(n+K==0) break;
 97         init();
 98         memset(has,0,sizeof(has));
 99         for(int i=0;i<n-1;i++)
100         {
101             scanf("%d%d%d",&u,&v,&l);
102             AddEdge(u,v,l);
103         }
104         root=0;son[0]=n;
105         getroot(1,1);//找重心
106         Ans=0;
107         dfs(root);
108         printf("%d\n",Ans);
109     }
110     return 0;
111 }

【poj1741】

—————————————————————————————————————————————————

【poj 1987】

和1741基本是一样一样的,无脑复制就好啦つ﹏?

不过稍微注意一下,要记得用%*d或%*s跳过多余的输入。

  1 #include<cmath>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 const int maxn=40010;
  6 using namespace std;
  7 struct  Edge
  8 {
  9     int nxt;
 10     int to;
 11     int w;
 12     Edge(){}
 13     Edge(int _to,int _nxt,int _w):to(_to),nxt(_nxt),w(_w){}
 14 }edge[maxn<<1];
 15 int head[maxn],tot;
 16 void init()
 17 {
 18     memset(head,-1,sizeof(head));
 19     tot=0;
 20 }
 21
 22 void AddEdge(int u,int v,int w)
 23 {
 24
 25     edge[tot]=Edge(v,head[u],w);
 26     head[u]=tot++;
 27     edge[tot]=Edge(u,head[v],w);
 28     head[v]=tot++;
 29 }
 30
 31 int son[maxn],siz[maxn],has[maxn],root;
 32 int n,K;
 33 void getroot(int u,int fa)
 34 {
 35     siz[u]=1;son[u]=0;
 36     for(int i=head[u];i!=-1;i=edge[i].nxt)
 37     {
 38         int v = edge[i].to;
 39         if(has[v]||v == fa) continue;
 40         getroot(v,u);
 41         siz[u] += siz[v];
 42         son[u] = max(son[u],siz[v]);
 43     }
 44     son[u] = max(son[u],son[0]-siz[u]);
 45     if(son[u]<son[root]) root=u;
 46 }
 47 int dis[maxn],res[maxn];
 48 void getdis(int u,int fa)
 49 {
 50     res[++res[0]]=dis[u];
 51     siz[u]=1;
 52     for(int i=head[u];i!=-1;i=edge[i].nxt)
 53     {
 54         int v=edge[i].to;
 55         if(has[v]||v==fa) continue;
 56         dis[v]=dis[u]+edge[i].w;
 57         getdis(v,u);
 58         siz[u]+=siz[v];
 59     }
 60 }
 61 int calc(int u,int init)//计算ans
 62 {
 63     dis[u]=init;res[0]=0;getdis(u,u);
 64     sort(res+1,res+1+res[0]);
 65     int l=1,r=res[0];
 66     int ans=0;
 67     while(l<r)
 68     {
 69         if(res[l]+res[r]<=K)
 70             ans+=r-l++;
 71         else
 72             --r;
 73     }
 74     return ans;
 75 }
 76 int Ans;
 77 void dfs(int u)
 78 {
 79     Ans+=calc(u,0);
 80     has[u]=1;
 81     for(int i=head[u];i!=-1;i=edge[i].nxt)
 82     {
 83         int v=edge[i].to;
 84         if(has[v]) continue;
 85         Ans-=calc(v,edge[i].w);
 86         root=0;son[0]=siz[v];
 87         getroot(v,v);
 88         dfs(root);
 89     }
 90 }
 91 int main()
 92 {
 93     while(~scanf("%d%*d",&n))
 94     {
 95         int u,v,l;
 96         if(n+K==0) break;
 97         init();
 98         memset(has,0,sizeof(has));
 99         for(int i=0;i<n-1;i++)
100         {
101             scanf("%d%d%d%*s",&u,&v,&l);
102             AddEdge(u,v,l);
103         }
104         scanf("%d",&K);
105         root=0;son[0]=n;
106         getroot(1,1);
107         Ans=0;
108         dfs(root);
109         printf("%d\n",Ans);
110     }
111     return 0;
112 }

【poj 1987】

—————————————————————————————————————————————————

【poj 2114】

题意:给定一棵边带权的树,求两点之间的距离刚好等于K的情况是否存在。

  1 #include<cmath>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 const int maxn=10010;
  6 using namespace std;
  7 struct  Edge
  8 {
  9     int nxt;
 10     int to;
 11     int w;
 12     Edge(){}
 13     Edge(int _to,int _nxt,int _w):to(_to),nxt(_nxt),w(_w){}
 14 }edge[maxn<<1];
 15 int head[maxn],tot;
 16 void init()
 17 {
 18     memset(head,-1,sizeof(head));
 19     tot=0;
 20 }
 21
 22 void AddEdge(int u,int v,int w)
 23 {
 24
 25     edge[tot]=Edge(v,head[u],w);
 26     head[u]=tot++;
 27     edge[tot]=Edge(u,head[v],w);
 28     head[v]=tot++;
 29 }
 30
 31 int son[maxn],siz[maxn],has[maxn],root;
 32 int n,K;
 33 void getroot(int u,int fa)
 34 {
 35     siz[u]=1;son[u]=0;
 36     for(int i=head[u];i!=-1;i=edge[i].nxt)
 37     {
 38         int v = edge[i].to;
 39         if(has[v]||v == fa) continue;
 40         getroot(v,u);
 41         siz[u] += siz[v];
 42         son[u] = max(son[u],siz[v]);
 43     }
 44     son[u] = max(son[u],son[0]-siz[u]);
 45     if(son[u]<son[root]) root=u;
 46 }
 47 int dis[maxn],res[maxn];
 48 void getdis(int u,int fa)
 49 {
 50     res[++res[0]]=dis[u];
 51     siz[u]=1;
 52     for(int i=head[u];i!=-1;i=edge[i].nxt)
 53     {
 54         int v=edge[i].to;
 55         if(has[v]||v==fa) continue;
 56         dis[v]=dis[u]+edge[i].w;
 57         getdis(v,u);
 58         siz[u]+=siz[v];
 59     }
 60 }
 61 int calc(int u,int init)//计算ans
 62 {
 63     dis[u]=init;res[0]=0;getdis(u,u);
 64     sort(res+1,res+1+res[0]);
 65     int l=1,r=res[0];
 66     int ans=0;
 67     while (l<r)
 68     {
 69         if(res[l]+res[r]==K)
 70         {
 71             if (res[l]==res[r])
 72             {
 73                 ans+=(r-l+1)*(r-l)/2;
 74                 break;
 75             }
 76             int i=l,j=r;
 77             while(res[l]==res[i]) ++i;
 78             while(res[r]==res[j]) --j;
 79             ans+=(i-l)*(r-j);
 80             l=i,r=j;
 81         }
 82         else if (res[l]+res[r]>K) r--;
 83         else  l++;
 84     }
 85     return ans;
 86 }
 87 int Ans;
 88 void dfs(int u)
 89 {
 90     has[u]=1;
 91     Ans+=calc(u,0);
 92     for(int i=head[u];i!=-1;i=edge[i].nxt)
 93     {
 94         int v=edge[i].to;
 95         if(has[v]) continue;
 96         Ans-=calc(v,edge[i].w);
 97         root=0;son[0]=siz[v];
 98         getroot(v,v);
 99         dfs(root);
100     }
101 }
102
103 int main()
104 {
105     while(~scanf("%d",&n)&&n)
106     {
107         int x,c;
108         init();
109         for(int i=1;i<=n;i++)
110         {
111             while(~scanf("%d",&x)&&x)
112             {
113                 scanf("%d",&c);
114                 AddEdge(i,x,c);
115             //    AddEdge(x,i,c);不用再反着存一遍了qwq
116             }
117         }
118         while(~scanf("%d",&K)&&K)
119         {
120             memset(has,0,sizeof(has));
121             Ans=root=0;
122             son[0]=n;
123             getroot(1,1);
124             dfs(root);
125             printf(Ans?"AYE\n":"NAY\n");
126         }
127         puts(".");
128     }
129     return 0;
130 }
131 /*
132 6
133 2 5 3 7 4 1 0
134 0
135 5 2 6 3 0
136 0
137 0
138 0
139 1
140 8
141 13
142 14
143 0
144 0
145 */

【poj 2114】

———————————————————————————————————————————————

/*

qwq就是这个题奇奇怪怪调了好久

跟机房dalao1号求助

dalao1号说这么长啊你给dalao2号吧

发给dalao2号

dalao2号看了一会儿说

我也看不出来你哪写错了你给dalao3号吧

于是发给dalao3号

dalao3号一看题目

愣了几秒说我可没写过点分治啊

……于是发给jdfz的dalao4号

dalao4号说你可以这样这样写

我按dalao4号的改了改发现还是TLE

实在没辙了qwq

最后我们家那口子某只Au爷说帮我看

过了几分钟……

Au爷:“来来来,我保证不打死你”

我:“啊啊啊不要打我啊我错了……”

被发现是把树存了4遍……

addedge函数里

我自己写了正着和反着加

结果main函数里读入时又存了两遍

所以才崩了啊啊啊

血与泪的教训

以后不能犯了(碎碎念qwq)

*/

时间: 2024-11-05 02:38:34

poj1741+poj1987+poj2114——点分治入门题集合的相关文章

COGS 577 蝗灾 [CDQ分治入门题]

题目链接 昨天mhr神犇,讲分治时的CDQ分治的入门题. 题意: 你又一个w*w正方形的田地. 初始时没有蝗虫. 给你两个操作: 1. 1 x y z: (x,y)这个位置多了z只蝗虫. 2. 2 x1 y1 x2 y2: 询问(x1,y1)到(x2,y2)这个矩形内的蝗虫数量. 其中 W<=500000,操作数<=200000 . 题解: w范围太大,无法使用二维数据结构. 于是我们可以分治操作. CDQ分治:定义 solve(l,r) 设m=(l+r)/2; 先计算 l-m 修改操作对 m

树点分治入门题poj1741

Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 24253   Accepted: 8060 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

poj 2524:Ubiquitous Religions(并查集,入门题)

Ubiquitous Religions Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 23997   Accepted: 11807 Description There are so many different religions in the world today that it is difficult to keep track of them all. You are interested in findi

HDU 1233 还是畅通工程【最小生成树入门题,Kruskal算法+Prim算法】

还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 39929    Accepted Submission(s): 18144 Problem Description 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路

poj1741(入门点分治)

题目链接:https://vjudge.net/problem/POJ-1741 题意:给出一棵树,求出树上距离不超过k的点对数量. 思路:点分治经典题.先找重心作为树根,然后求出子树中所有点到重心的距离dis[i],那么所有组合为dis[i]+dis[j]<=k,其中不合法组合为在重心的同一个子树内的情况,所以要减去在重心的子树中仍满足dis[i]+dis[j]<=k的情况. AC代码: #include<cstdio> #include<algorithm> #in

hdu 2767 Proving Equivalences(强连通入门题)

1 /************************************************* 2 Proving Equivalences(hdu 2767) 3 强连通入门题 4 给个有向图,求至少加多少条边使得图是所有点都是强连通的 5 由a->b->c->a易知n个点至少要n条边,每个出度和入度都要大 6 于1.先求所有所有强连通分量,把每个强连通分量看成一个点 7 在找每个点的出度和入度,最后还差的出度和入度的最大值就是 8 答案. 9 10 ************

hdu 5001 walk 概率dp入门题

Description I used to think I could be anything, but now I know that I couldn't do anything. So I started traveling. The nation looks like a connected bidirectional graph, and I am randomly walking on it. It means when I am at node i, I will travel t

BZOJ2152 点分治入门

点分治基本思路: ①对每个点, 计算经过它的满足题目要求的链的条数, 所有点的答案加起来刚好不重不漏地统计了整棵树中满足条件的点数 ②计算方法:先算出一颗树上经过了根(根找重心,树比较平衡)的满足条件的链的数量(可以分治), 然后打上标记(每次递归下去时如果遇到标记就停止, 相当于将树从这个位置断开分成了多棵子树,分别处理这些子树), 减去仅在子树中(即没有过根)的满足条件的链(递归下去) 本题目统计cnt[i]表示现在为止(可以一边递归同时一边更新)到根距离 %3 = i的点数, 则可以构成的

hdu1796:容斥入门题

简单的容斥入门题.. 容斥基本的公式早就知道了,但是一直不会写. 下午看到艾神在群里说的“会枚举二进制数就会容斥”,后来发现还真是这样.. 然后直接贴代码了 #include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #include<ctype.h> using namespace std; long l