CodeForces
来源:互联网 发布:彩弹枪淘宝有么 编辑:程序博客网 时间:2024/06/02 00:23
题意:
一棵树上 告诉你边权。
问你有多少点对满足的路上的权值之和 小于等于w, 边数小于等于L。
思路:
显然树上的点分治。
和男人八题一样, 只不过多加了一个边数小于等于L的限制。(一维限制变成二维限制)
做法肯定还是一样。
只不过在求经过重心满足要求点对时有点变化 (其余算法 看上一篇文章)。。
分析一下, 因为边权最大1e9, 边数最大1e5 , 因此, 边数这一个限制,我们可以用数据结构干掉。
因此按照边权w 从小到大排序。
初始状态 把所有的边数 加到 线段树里或者树状数组里, 然后双指针在移动时, 移动一个删一个。
双指针里肯定是边权符合要求的, 要想边数也符合, 直接数据结构查询即可。
注意:
分治的时候就不能在分治一次初始化数据结构一次了。 TLE了两发T_T
分析一下, 初始化数据结构肯定时o(nlogn)的 ,最后双指针肯定移动到一块去, 因此 最后数据结构里最多只有 最后指针那个位置不为空。 log n 删一下即可。
吐槽:
能用树状数组就别用线段树, 慢的两倍多= =!!!!
#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int maxn = 100000 + 10;int n, l;long long w;vector<pair<int,int> >g[maxn];long long ans;int vis[maxn];int siz[maxn];int mx[maxn];///=======================/// 树状数组int c[maxn];inline int lowbit(int x){ return x&-x;}int SUM(int x){ int ans = 0; while(x){ ans += c[x]; x -= lowbit(x); } return ans;}void ADD(int x,int add){ while(x <= l+1){ c[x] += add; x += lowbit(x); }}///=======================void getsize(int cur,int fa){ siz[cur] = 1; mx[cur] = 0; for (int i = 0; i < g[cur].size(); ++i){ int v = g[cur][i].first; if (v != fa && !vis[v]){ getsize(v, cur); siz[cur] += siz[v]; if (siz[v] > mx[cur]){ mx[cur] = siz[v]; } } }}int root, mi;void find(int rt, int cur,int fa){ /// 找以rt 为根的树的重心。 mx[cur] = max(mx[cur], siz[rt] - siz[cur]); if (mx[cur] < mi){ mi = mx[cur]; root = cur; } for (int i = 0; i < g[cur].size(); ++i){ int v = g[cur][i].first; if (v != fa && !vis[v]){ find(rt, v, cur); } }}struct node{ /// 距离变成了一个二维的偏序关系。 long long d1; int d2; node(long long d1 = 0,int d2 = 0):d1(d1), d2(d2){}};bool cmp(node a, node b){ /// 按边权排序 return a.d1 < b.d1;}node dis[maxn];int cnt;void getdis(int cur,long long d1, int d2, int fa){ dis[cnt++] = node(d1, d2); for (int i = 0; i < g[cur].size(); ++i){ int v = g[cur][i].first; int w = g[cur][i].second; if (v != fa && !vis[v]){ getdis(v, d1 + w, d2 + 1, cur); } }}long long solve(int cur,long long d1,int d2){ long long ret = 0; cnt = 0; getdis(cur, d1, d2, 0); sort(dis, dis + cnt, cmp);// memset(c,0,sizeof c); int i = 0, j = cnt - 1; for (int i = 0; i < cnt; ++i){ ADD(dis[i].d2+1, 1); } while(i < j){ ADD(dis[i].d2+1, -1); while(i < j && dis[i].d1 + dis[j].d1 > w){ ADD(dis[j].d2+1, -1); --j; } if (l - dis[i].d2 >= 0){ int tmp = SUM(l-dis[i].d2+1); ret += tmp; } ++i; } if (SUM(dis[j].d2 + 1))ADD(dis[j].d2+1,-1); /// *****只需要特判一下 就可以完全清空树状数组,不能memset, 会超时!!! return ret;}const int inf = 0x3f3f3f3f;void dfs(int cur){ getsize(cur, 0); mi = inf; find(cur, cur, 0); ans += solve(root, 0, 0);// printf("root = %d\n", root); vis[root] = 1; int tmproot = root; for (int i = 0; i < g[tmproot].size(); ++i){ int v = g[tmproot][i].first; int w = g[tmproot][i].second; if (!vis[v]){ ans -= solve(v, w, 1); dfs(v); } }}int main(){ scanf("%d %d %lld", &n, &l, &w); for (int i = 1; i < n; ++i){ int x,y; scanf("%d %d",&x, &y); g[x].push_back(make_pair(i+1, y)); g[i+1].push_back(make_pair(x, y)); } dfs(1); printf("%lld\n", ans); return 0;}
阅读全文
0 0
- codeforces~~~
- Codeforces
- codeforces
- Codeforces
- codeforces
- codeforces
- Codeforces
- Codeforces
- CodeForces
- CodeForces
- CodeForces
- CodeForces
- CodeForces
- Codeforces
- Codeforces
- Codeforces
- Codeforces
- Codeforces
- Linux 之 nohup 命令
- CSS实现文本溢出的部分用省略号代替的方法
- 多线程基本内容(一)
- ffmpeg 播放rtsp流认证问题
- ##* %%* linux变量处理
- CodeForces
- HDU1021(规律题)
- ASP.NET、.NET和C#的关系
- yolo v2之车牌检测后续识别字符(二)
- HDU 1156 Brownie Points II
- POJ2243 Knight Moves(A*算法)
- An error occurred while collecting items to be installed session context was:(profile=epp.package.je
- Hive的collect_set使用详解
- ListView保存并还原焦点