P3242 [HNOI2015]接水果

题目描述

风见幽香非常喜欢玩一个叫做 \(osu!\) 的游戏,其中她最喜欢玩的模式就是接水果。由于她已经\(DT\) \(FC\) 了\(\tt{The\ big\ black}\), 她觉得这个游戏太简单了,于是发明了一个更加难的版本。

首先有一个地图,是一棵由 \(n\) 个顶点、\(n-1\) 条边组成的树(例如图 \(1\) 给出的树包含 \(8\) 个顶点、\(7\) 条边)。

这颗树上有 \(P\) 个盘子,每个盘子实际上是一条路径(例如图 \(1\) 中顶点 \(6\) 到顶点 \(8\) 的路径),并且每个盘子还有一个权值。第 \(i\) 个盘子就是顶点\(a_i\)到顶点\(b_i\)的路径(由于是树,所以从\(a_i\)到\(b_i\)的路径是唯一的),权值为\(c_i\)。

接下来依次会有\(Q\)个水果掉下来,每个水果本质上也是一条路径,第\(i\) 个水果是从顶点 \(u_i\) 到顶点\(v_i\) 的路径。

幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如图\(1\)中从 \(3\)到\(7\) 的路径是从\(1\)到\(8\)的路径的子路径)。这里规定:从 \(a\) 到\(b\)的路径与从\(b\)到 \(a\)的路径是同一条路径。

当然为了提高难度,对于第 \(i\) 个水果,你需要选择能接住它的所有盘子中,权值第 \(k_i\) 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?

输入输出格式

输入格式:

第一行三个数 \(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\)不等于\(b\)。

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

输出格式:

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

说明

\(N,P,Q\le 40000\)。


细节真多\(\tt{XD}\)

考虑如何处理路径包含关系。

设被包含的路径为\((u,v)\),要去包含\(\tt{Ta}\)的路径为\((s,t)\),\(dfn_x\)和\(low_x\)分别表示\(x\)的\(dfs\)序和\(\tt{Ta}\)子树的\(dfs\)序末尾。

这里需要维护路径二元组的有序性,我们令前一维的点的\(dfs\)序更小。

对被包含的路径进行分类讨论

  1. 若\(lca(u,v)=u\)

    设\(w\)为\(u\)的第一个儿子且\(w\)为\(v\)的祖先

    那么若满足包含关系,需满足

    \(dfn_v \le dfn_t \le low_v\)且\(1 \le dfs_s \le dfn_w -1\)

    或者\(low_w+1\le dfn_s \le n\)且\(dfn_v \le dfn_t \le low_v\)

    (这里顺序是个小细节)

  2. 若\(lca(u,v)\not=u\)

    则需要满足\(dfn_v\le dfn_s \le low_v\)且\(dfn_u \le dfn_t \le low_t\)

发现可以把限制条件转换到二维数点之类的问题。

具体的,可以把被包含的路径(盘子)转换成矩形,包含别人的路径(水果)转换成点。

那么问题就转化成了包含某个点的矩形的第\(k\)小值。

我们可以整体二分,内部的问题是某个点被多少个矩形包含,可以使用扫描线求解。

这里扫描线差分一下用树状数组就可以了。


Code:

#include <cstdio>
#include <cctype>
#include <algorithm>
const int N=40010;
int Next[N<<1],to[N<<1],head[N],cnt;
void add(int u,int v)
{
to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int read()
{
char c=getchar();int x=0;
while(!isdigit(c)) c=getchar();
while(isdigit(c)) {x=x*10+c-'0';c=getchar();}
return x;
}
int dep[N],f[N][17],dfn[N],low[N],dfsclock;
int n,m,Q,ans[N];
void dfs(int now)
{
dfn[now]=++dfsclock;
for(int i=1;f[now][i-1];i++) f[now][i]=f[f[now][i-1]][i-1];
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
if(v==f[now][0]) continue;
dep[v]=dep[now]+1;
f[v][0]=now;
dfs(v);
}
low[now]=dfsclock;
}
int LCA(int x,int y)
{
if(dep[x]<dep[y]) return LCA(y,x);
for(int i=16;~i;i--)
if(dep[f[x][i]]>=dep[y])
x=f[x][i];
if(x==y) return x;
for(int i=16;~i;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int get(int x,int y)
{
for(int i=16;~i;i--)
if(dep[f[x][i]]>dep[y])
x=f[x][i];
return x;
}
struct node
{
int op,x,l,r,k,d;//盘子,大的做x,区间,权值,线的性质
//第几个水果,横,纵,留空,第k小,留空
node(){}
node(int op,int x,int l,int r,int k,int d){this->op=op,this->x=x,this->l=l,this->r=r,this->k=k,this->d=d;}
bool friend operator <(node n1,node n2)
{
if(n1.x==n2.x)//先盘子,再水果,盘子中先取消失线
return n1.op==n2.op?n1.d<n2.d:n1.op<n2.op;
return n1.x<n2.x;
}
}q[N<<3],ql[N<<3],qr[N<<3];
int S[N],tmp;
void Swap(int &x,int &y){tmp=x,x=y,y=tmp;}
void change(int x,int d){while(x<=n)S[x]+=d,x+=x&-x;}
int query(int x){int sum=0;while(x)sum+=S[x],x-=x&-x;return sum;}
#define rep(i,a,b) for(int i=a;i<=b;i++)
void divide(int l,int r,int s,int t)
{
if(s>t) return;
if(l==r){rep(i,s,t)ans[q[i].op]=l;return;}
int mid=l+r>>1,lp=0,rp=0;
rep(i,s,t)
{
if(q[i].op)
{
int c=query(q[i].l);
if(c>=q[i].k) ql[++lp]=q[i];
else qr[++rp]=q[i],qr[rp].k-=c;
}
else
{
if(q[i].k<=mid) change(q[i].l,q[i].d),change(q[i].r+1,-q[i].d),ql[++lp]=q[i];
else qr[++rp]=q[i];
}
}
rep(i,s,t) if(!q[i].op&&q[i].k<=mid) change(q[i].l,-q[i].d),change(q[i].r+1,q[i].d);
rep(i,s,s+lp-1) q[i]=ql[i+1-s];
rep(i,s+lp,t) q[i]=qr[i+1-s-lp];
divide(l,mid,s,s+lp-1),divide(mid+1,r,s+lp,t);
}
int main()
{
n=read(),m=read(),Q=read();
int u,v,k,w,lca,t=0;rep(i,1,(n-1))u=read(),v=read(),add(u,v),add(v,u);
dep[1]=1,dfs(1);
rep(i,1,m)
{
u=read(),v=read(),k=read();
if(dfn[u]>dfn[v]) Swap(u,v);
lca=LCA(u,v);
if(lca==u)
{
w=get(v,u);
q[++t]=node(0,1,dfn[v],low[v],k,1);
q[++t]=node(0,dfn[w],dfn[v],low[v],k,-1);
q[++t]=node(0,dfn[v],low[w]+1,n,k,1);
q[++t]=node(0,low[v]+1,low[w]+1,n,k,-1);
}
else
{
q[++t]=node(0,dfn[u],dfn[v],low[v],k,1);
q[++t]=node(0,low[u]+1,dfn[v],low[v],k,-1);
}
}
rep(i,1,Q)
{
q[++t].x=dfn[read()],q[t].l=dfn[read()],q[t].k=read(),q[t].op=i;
if(q[t].x>q[t].l) Swap(q[t].x,q[t].l);
}
std::sort(q+1,q+1+t);
divide(0,(int)(1e9),1,t);
rep(i,1,Q) printf("%d\n",ans[i]);
return 0;
}

2018.11.4

洛谷 P3242 [HNOI2015]接水果 解题报告的更多相关文章

  1. [洛谷P3242] [HNOI2015]接水果

    洛谷题目链接:[HNOI2015]接水果 题目描述 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果.由于她已经DT FC 了The big black, 她觉得这个游戏太简 ...

  2. ●洛谷P3242 [HNOI2015]接水果

    题链: https://www.luogu.org/problemnew/show/P3242 题解: 整体二分,扫描线+树状数组. 详细的题解:http://blog.csdn.net/thy_as ...

  3. 洛谷_Cx的故事_解题报告_第四题70

    1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h>   struct node {     long x,y,c; ...

  4. 洛谷 P2317 [HNOI2005]星际贸易 解题报告

    P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...

  5. 洛谷 P3802 小魔女帕琪 解题报告

    P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...

  6. 洛谷 P2606 [ZJOI2010]排列计数 解题报告

    P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...

  7. 洛谷1303 A*B Problem 解题报告

    洛谷1303 A*B Problem 本题地址:http://www.luogu.org/problem/show?pid=1303 题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式 ...

  8. 洛谷 P3084 [USACO13OPEN]照片Photo 解题报告

    [USACO13OPEN]照片Photo 题目描述 农夫约翰决定给站在一条线上的\(N(1 \le N \le 200,000)\)头奶牛制作一张全家福照片,\(N\)头奶牛编号\(1\)到\(N\) ...

  9. 洛谷 P1379 八数码难题 解题报告

    P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...

随机推荐

  1. node环境清空控制台的代码

    process.stdout.write( process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H' );

  2. C# Builder

    如下: class Program { static void Main(string[] args) { ).BuildB(2.1).BuildUp(); Console.Read(); } } p ...

  3. Java多线程之volatile与synchronized比较

    可见性: JAVA内存模型: java为了加快程序的运行效率,对一些变量的操作是在寄存器或者CPU缓存上进行的,后面再同步到主存中 看上图,线程在运行的过程中,会从主内存里面去去变量,读到自己的空间内 ...

  4. Linux命令应用大词典-第16章 归档和压缩

    16.1 tar:进行归档和压缩 16.2 gzip:压缩或解压缩gzip文件 16.3 gunzip:解压缩gzip文件 16.4 zcmp:比较gzip压缩文件 16.5 zdiff:比较gzip ...

  5. [Clr via C#读书笔记]Cp13接口

    Cp13接口 类和接口继承 接口只提供签名,不提供实现:等效于契约:凡事能使用具名接口的地方都能够使用实现了的接口. 定义接口 定义很简单,FCL也提供了大量的现成接口供使用: 继承接口 类不能多继承 ...

  6. ionic typescript--验证码发送倒计时功能

    1.新建页面 ionic g page forget   2.mode.html文件 <ion-item> <ion-input clearInput [(ngModel)]='co ...

  7. 饥饿的小易(枚举+广度优先遍历(BFS))

    题目描述 小易总是感觉饥饿,所以作为章鱼的小易经常出去寻找贝壳吃.最开始小易在一个初始位置x_0.对于小易所处的当前位置x,他只能通过神秘的力量移动到 4 * x + 3或者8 * x + 7.因为使 ...

  8. 机器学习-聚类Clustering

    简介 前面介绍的线性回归,SVM等模型都是基于数据有标签的监督学习方法,本文介绍的聚类方法是属于无标签的无监督学习方法.其他常见的无监督学习还有密度估计,异常检测等. 聚类就是对大量未知标注的数据集, ...

  9. tensorflow学习笔记(4)-学习率

    tensorflow学习笔记(4)-学习率 首先学习率如下图 所以在实际运用中我们会使用指数衰减的学习率 在tf中有这样一个函数 tf.train.exponential_decay(learning ...

  10. 测试报告M2

    1,项目简介我们已经在第一次测试报告中说过,这一次主要说一下场景测试实例 1.1测试人员 测试人员包括团队开发小组成员以及特邀测试用户组. 1)  团队内部测试主要针对网站支持的各功能组件进行一一测试 ...