首页 > BZOJ 4009 接水果

BZOJ 4009 接水果

Description

风见幽香非常喜欢玩一个叫做osu!的游戏,其中她最喜欢玩的模式就是接水果。

由于她已经DT FC了The big black, 她觉得这个游戏太简单了,于是发明了一个更加难的版本。首先有一个地图,是一棵由(n)个顶点、(n-1)条边组成的树。这颗树上有(P)个盘子,每个盘子实际上是一条路径,并且每个盘子还有一个权值。第(i)个盘子就是顶点(a_{i})到顶点(b_{i})的路径(由于是树,所以从(a_{i})(b_{i})的路径是唯一的),权值为(c_{i})。接下来依次会有(Q)个水果掉下来,每个水果本质上也是一条路径,第(i)个水果是从顶点(u_{i})到顶点(v_{i})的路径。幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径。这里规定:从(a)(b)的路径与从(b)(a)的路径是同一条路径。当然为了提高难度,对于第(i)个水果,你需要选择能接住它的所有盘子中,权值第(k_{i})小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?

Input

第一行三个数(n,P)(Q),表示树的大小和盘子的个数和水果的个数。

接下来(n-1)行,每行两个数(a,b),表示树上的(a)(b) 之间有一条边。树中顶点按(1)(n)标号。接下来(P)行,每行三个数(a,b,c),表示路径为(a)(b)、权值为(c)的盘子,其中(0 le c le 10^{9},a eq b)

接下来(Q)行,每行三个数(u,v,k),表示路径为(u)(v)的水果,其中(u eq v),你需要选择第(k)小的盘子,第(k)小一定存在。

Output

对于每个果子,输出一行表示选择的盘子的权值。

Sample Input

10 10 10

1 2

2 3

3 4

4 5

5 6

6 7

7 8

8 9

9 10

3 2 217394434

10 7 13022269

6 7 283254485

6 8 333042360

4 6 442139372

8 3 225045590

10 4 922205209

10 8 808296330

9 2 486331361

4 9 551176338

1 8 5

3 8 3

3 8 4

1 8 3

4 8 1

2 3 1

2 3 1

2 3 1

2 4 1

1 4 1

Sample Output

442139372

333042360

442139372

283254485

283254485

217394434

217394434

217394434

217394434

217394434

Hint

(N,P,Q le 40000)

整体二分。对于区间(l sim r),二分值域(mid),将(le mid)的盘子加入,每个水果的(k)与其路径上存在的盘子数进行比较,若多了该询问往左区间(l sim mid)递归,否则往右区间(mid+1 sim r)递归。

现在的问题就是如何判定每个水果的(k)与其路径上存在的盘子数的大小关系。考虑每个盘子,覆盖的路径为(a_{i})(b_{i})(dep_{a_{i}} < dep_{b_{i}})),那么这个盘子所贡献的水果只有可能两种情况:

(1.b_{i})(a_{i})的子树内,那么水果的两个端点(u,v)必须一个(b_{i})的子树内,一个在(a_{i})的子树外(可以包括(a_{i}))。

(2.)否则,两个点必须一个在(a_{i})的子树内,一个在(b_{i})的子树内。

看到有子树的东西,马上想到dfs序。由于这个dfs序是一段连续的区间,所以我们可以将盘子根据dfs序抽象成为矩形(情况一上两个不相交的矩形,情况二是一个矩形),将水果抽象成为一个点,每次检验即询问点被多少矩形所覆盖。扫描线+树状数组即可解决。

注意:矩形必须保证(x)坐标小于(y)坐标。

#include
#include
#include
#include
using namespace std;#define maxn (40010)
int N,P,Q,side[maxn],next[maxn*2],toit[maxn*2],dep[maxn],tree[maxn];
int L[maxn],R[maxn],ans[maxn],f[maxn][20],Ts,cnt,tot,have[maxn],sum[maxn];
struct SCAN
{int X,Y1,Y2,sign,be;friend inline bool operator <(const SCAN &a,const SCAN &b) { return a.X != b.X?a.X < b.X:a.sign>= 1,++i) if (step&1) a = f[a][i];return a;
}inline int lowbit(int a) { return a&-a; }
inline void modify(int a,int b) { for (;a <= N;a += lowbit(a)) tree[a] += b; }
inline int calc(int a) { int ret = 0; for (;a;a -= lowbit(a)) ret += tree[a]; return ret; }struct NODE
{int a,b,c,id;friend inline bool operator <(const NODE &x,const NODE &y) { return x.c < y.c; }inline void read(int i) { scanf("%d %d %d",&a,&b,&c); id = i; }inline void update() { if (L[a] > L[b]) swap(a,b); }inline void ins1() { bac[++tot] = (SCAN){L[a],L[b],L[b],0,id}; }inline void ins2() { for (int i = 0;i < have[id];++i) bac[++tot] = save[id][i]; }inline void change(){if (L[b] >= L[a]&&L[b] <= R[a]){int son = jump(b,dep[b]-dep[a]-1);if (L[son] > 1){save[id][have[id]++] = (SCAN){1,L[b],R[b],-1,id};save[id][have[id]++] = (SCAN){L[son]-1,L[b],R[b],1,id};}if (R[son] < N){save[id][have[id]++] = (SCAN){L[b],R[son]+1,N,-1,id};save[id][have[id]++] = (SCAN){R[b],R[son]+1,N,1,id};}}else{save[id][have[id]++] = (SCAN){L[a],L[b],R[b],-1,id};save[id][have[id]++] = (SCAN){R[a],L[b],R[b],1,id};}}
}path[maxn],query[maxn],tmp[maxn];inline void add(int a,int b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; }
inline void ins(int a,int b) { add(a,b); add(b,a); }inline void dfs(int now)
{L[now] = ++Ts;for (int i = 1;(1 << i) <= dep[now];++i) f[now][i] = f[f[now][i-1]][i-1];for (int i = side[now];i;i = next[i])if (toit[i] != f[now][0])f[toit[i]][0] = now,dep[toit[i]] = dep[now]+1,dfs(toit[i]);R[now] = Ts;
}inline void census(int ql,int qr,int pl,int pr,int &ll,int &rr)
{tot = 0;for (int i = pl;i <= pr;++i) path[i].ins2();for (int i = ql;i <= qr;++i) query[i].ins1();sort(bac+1,bac+tot+1);for (int i = 1;i <= tot;++i){if (!bac[i].sign) sum[bac[i].be] = calc(bac[i].Y1);else modify(bac[i].Y1,-bac[i].sign),modify(bac[i].Y2+1,bac[i].sign);}for (int i = ql;i <= qr;++i){if (sum[query[i].id] >= query[i].c) tmp[++ll] = query[i];else query[i].c -= sum[query[i].id],tmp[--rr] = query[i];sum[query[i].id] = 0;}for (int i = ql;i <= qr;++i) query[i] = tmp[i];for (int i = 1;i <= tot;++i)if (bac[i].sign) modify(bac[i].Y1,bac[i].sign),modify(bac[i].Y2+1,-bac[i].sign);
}inline void work(int ql,int qr,int pl,int pr)
{if (ql > qr) return;if (pl == pr){for (int i = ql;i <= qr;++i) ans[query[i].id] = path[pl].c;return;}int ll = ql-1,rr = qr+1,mid = (pl + pr)>>1;census(ql,qr,pl,mid,ll,rr);work(ql,ll,pl,mid); work(rr,qr,mid+1,pr);
}int main()
{freopen("fruit.in","r",stdin);freopen("fruit.out","w",stdout);scanf("%d %d %d",&N,&P,&Q);for (int i = 1,a,b;i < N;++i) scanf("%d %d",&a,&b),ins(a,b);dfs(1);for (int i = 1;i <= P;++i) path[i].read(i),path[i].update(),path[i].change();sort(path+1,path+P+1);for (int i = 1;i <= Q;++i) query[i].read(i),query[i].update();work(1,Q,1,P);for (int i = 1;i <= Q;++i) printf("%d
",ans[i]);fclose(stdin); fclose(stdout);return 0;
}

转载于:https://www.cnblogs.com/mmlz/p/4448719.html

更多相关:

  •         Apache POI是一个开源的利用Java读写Excel,WORD等微软OLE2组件文档的项目。        我的需求是对Excel的数据进行导入或将数据以Excel的形式导出。先上简单的测试代码:package com.xing.studyTest.poi;import java.io.FileInputSt...

  • 要取得[a,b)的随机整数,使用(rand() % (b-a))+ a; 要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a; 要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1; 通用公式:a + rand() % n;其中的a是起始值,n是整数的范围。 要取得a到b之间的...

  • 利用本征图像分解(Intrinsic Image Decomposition)算法,将图像分解为shading(illumination) image 和 reflectance(albedo) image,计算图像的reflectance image。 Reflectance Image 是指在变化的光照条件下能够维持不变的图像部分...

  • 题目:面试题39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制: 1 <= 数组长度 <= 50000 解题: cl...

  • 题目:二叉搜索树的后序遍历序列 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。 参考以下这颗二叉搜索树:      5     /    2   6   /  1   3示例 1: 输入: [1,6,3,2,5] 输出...

  •     先吐为敬!   最近心血来潮研究nodejs如何完成微信支付功能,结果网上一搜索,一大堆“代码拷贝党”、“留一手”、“缺斤少两”、“不说人话”、“自己都没跑通还出来发blog”、“各种缺少依赖包”、“各种注释都没有”、“自己都不知道在写什么”的程序大神纷纷为了增加自己博客一个帖子的名额而发布了各种千奇百�...

  • 阅读ceph源码过程中需要明确当前操作是由哪个线程发出,此时需要根据线程id来确认线程名称 C++获取线程id是通过系统调用来直接获取 函数描述 头文件: 函数名称:syscall(SYS_gettid) 该函数直接返回了一个pid_t int类型的数字,即为当前线程id 此外函数pthread_s...

  • 面试题 分库分表之后,id 主键如何处理? 面试官心理分析 其实这是分库分表之后你必然要面对的一个问题,就是 id 咋生成?因为要是分成多个表之后,每个表都是从 1 开始累加,那肯定不对啊,需要一个全局唯一的 id 来支持。所以这都是你实际生产环境中必须考虑的问题。 面试题剖析 基于数据库的实现方案 数据库自增 id 这个就是说你的...

  • ORM操作    单表、一对多表操作 1 from django.db import models 2 3 4 class UserGroup(models.Model): 5 title = models.CharField(max_length=32) 6 7 8 class UserInfo(m...

  • 建立如下表: 建表语句: class表创建语句 create table class(cid int not null auto_increment primary key, caption varchar(32) not null)engine=innodb default charset=utf8;student表创建语句 c...