题面

传送门

思路

本题其实有在线做法......但是太难写了,退而求其次写了离线

基本思路就是,考虑一个盘子以及它能接到的所有水果

可以发现,这个水果的端点一定在这个盘子两端的“子树”内(加引号是因为可能是一条链顶端外面的“子树”)

那么,可以把模型抽象成:盘子就是矩形,两个端点就是两个维度上的限制,而水果就是点

一个水果可以被接住,当且仅当这个水果的点在某个盘子的矩形内部

考虑盘子的不同情况:

如果盘子是有一个折点的折链,那么两边的限制,就是两个端点的子树dfs序范围

如果盘子是一条从下到上的链,那么这个矩形实际上是有两个的:

假设链是(u,v),u是v的祖先,这条链上从u开始下一个点是x

那么,其中一维的限制显然是$[dfn[v],last[v]]$,

但是另一维上的限制实际上有两个拼起来:

$[1,dfn[x]-1]$和$[last[x]+1,n]$

这里实际上是得到了$u$外面的“子树”的dfs序范围

我们把这些链拆成矩形,然后跑一个整体二分,每次二分每个水果被多少个矩形覆盖

当前二分区间是$[l,r]$,如果$[l,mid]$中的覆盖矩形的数量大于要求的数量,就进入左边

否则,要求的数量减去这个覆盖矩形数量,并进入右边

这样总复杂度是$O(n\log^2n)$

实现的时候,可以把矩形的两个维度中小的那个放在x,大的放在y,注意这里不要写错了

Code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<queue>
#include<cmath>
#define las DEEP_DARK_FANTASY
#define lowbit(x) (x&(-x))
#define mp make_pair
using namespace std;
namespace IO
{
const int __S=(1<<20)+5;char __buf[__S],*__H,*__T;
inline char getc()
{
if(__H==__T) __T=(__H=__buf)+fread(__buf,1,__S,stdin);
if(__H==__T) return -1;
return *__H++;
}
template <class __I>inline void read(__I &__x)
{
__x=0;int __fg=1;char __c=getc();
while(!isdigit(__c)&&__c!='-') __c=getc();
if(__c=='-') __fg=-1,__c=getc();
while(isdigit(__c)) __x=__x*10+__c-'0',__c=getc();
__x*=__fg;
}
inline void readd(double &__x)
{
__x=0;double __fg=1.0;char __c=getc();
while(!isdigit(__c)&&__c!='-') __c=getc();
if(__c=='-') __fg=-1.0,__c=getc();
while(isdigit(__c)) __x=__x*10.0+__c-'0',__c=getc();
if(__c!='.'){__x=__x*__fg;return;}else while(!isdigit(__c)) __c=getc();
double __t=1e-1;while(isdigit(__c)) __x=__x+1.0*(__c-'0')*__t,__t=__t*0.1,__c=getc();
__x=__x*__fg;
}
inline void reads(char *__s,int __x)
{
char __c=getc();int __tot=__x-1;
while(__c<'a'||__c>'z') __c=getc();
while(__c>='a'&&__c<='z') __s[++__tot]=__c,__c=getc();
__s[++__tot]='\0';
}
char __obuf[__S],*__oS=__obuf,*__oT=__oS+__S-1,__c,__qu[55];int __qr;
inline void flush(){fwrite(__obuf,1,__oS-__obuf,stdout);__oS=__obuf;}
inline void putc(char __x){*__oS++ =__x;if(__oS==__oT) flush();}
template <class __I>inline void print(__I __x)
{
if(!__x) putc('0');
if(__x<0) putc('-'),__x=-__x;
while(__x) __qu[++__qr]=__x%10+'0',__x/=10;
while(__qr) putc(__qu[__qr--]);
}
inline void prints(const char *__s,const int __x)
{
int __len=strlen(__s+__x);
for(int __i=__x;__i<__len+__x;__i++) putc(__s[__i]);
}
inline void printd(long double __x,int __d)
{
long long __t=(long long)floor(__x);print(__t);putc('.');__x-=(double)__t;
while(__d--)
{
long double __y=__x*10.0;__x*=10.0;
int __c=(int)floor(__y+1e-9);if(__c==10) __c--;
putc(__c+'0');__x-=floor(__y);
}
}
inline void el(){putc('\n');}inline void sp(){putc(' ');}
}using namespace IO; inline int read(){
int re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
int n,m,k,first[40010],cnte,dfn[40010],las[40010],st[40010][20],dep[40010],clk;
struct edge{
int to,next;
}a[100010];
inline void add(int u,int v){
a[++cnte]=(edge){v,first[u]};first[u]=cnte;
a[++cnte]=(edge){u,first[v]};first[v]=cnte;
}
void dfs(int u,int f){
int i,v;
st[u][0]=f;dep[u]=dep[f]+1;
dfn[u]=++clk;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(v==f) continue;
dfs(v,u);
}
las[u]=clk;
}
void ST(){
int i,j;
for(j=1;j<=16;j++)
for(i=1;i<=n;i++)
st[i][j]=st[st[i][j-1]][j-1];
}
int getpre(int l,int r){
int i;
if(l==r) return l;
if(dep[l]>dep[r]) swap(l,r);
for(i=16;i>=0;i--) if(dep[st[r][i]]>dep[l]) r=st[r][i];
if(st[r][0]==l) return r;
else return 0;
}
struct mat{
int lx,rx,ly,ry,val,id;
}p[100010];int cntp;
inline bool cmp(mat l,mat r){
return l.val<r.val;
}
struct fru{
int x,y,id,ans,k;
}f[40010];
struct ele{
int l,r,id;
};
namespace BIT{
int a[100010];
void Add(int x,int val){
for(;x<=n;x+=lowbit(x)) a[x]+=val;
}
void add(int l,int r,int val){
Add(l,val);Add(r+1,-val);
}
int sum(int x){
int re=0;
for(;x>0;x-=lowbit(x)) re+=a[x];
return re;
}
}
queue<ele>q;
vector<int>s,le,ri;
vector<pair<int,int> >t;
inline bool cmps(int l,int r){
return f[l].x<f[r].x;
}
inline bool cmpt(pair<int,int>l,pair<int,int>r){
int vl,vr;
if(l.second) vl=p[l.first].rx;
else vl=p[l.first].lx;
if(r.second) vr=p[r.first].rx;
else vr=p[r.first].lx;
return vl<vr;
}
void solve(){
ele cur;int i,l,r,mid,j,tmp,tval;
for(i=1;i<=k;i++) q.push((ele){1,cntp,i}); while(!q.empty()){
cur=q.front();q.pop();
if(cur.l==cur.r){f[cur.id].ans=p[cur.l].val;continue;}
l=cur.l;
r=cur.r;
s.clear();
s.push_back(cur.id);
mid=(l+r)>>1;t.clear(); while(!q.empty()&&q.front().l==l&&q.front().r==r){
s.push_back(q.front().id);
q.pop();
}
sort(s.begin(),s.end(),cmps); for(i=l;i<=mid;i++){
t.push_back(mp(i,0));
t.push_back(mp(i,1));
}
sort(t.begin(),t.end(),cmpt); j=-1;le.clear();ri.clear();
for(i=0;i<t.size();i++){
if(t[i].second) tmp=p[t[i].first].rx;
else tmp=p[t[i].first].lx; while((j<((int)s.size()-1))&&(f[s[j+1]].x<tmp)){
j++;tval=BIT::sum(f[s[j]].y);
if(tval<f[s[j]].k){
f[s[j]].k-=tval;
ri.push_back(s[j]);
}
else{
le.push_back(s[j]);
}
}
if(t[i].second) BIT::add(p[t[i].first].ly,p[t[i].first].ry,-1);
else BIT::add(p[t[i].first].ly,p[t[i].first].ry,1);
}
while(j<((int)s.size()-1)){
j++;tval=BIT::sum(f[s[j]].y);
if(tval<f[s[j]].k){
f[s[j]].k-=tval;
ri.push_back(s[j]);
}
else{
le.push_back(s[j]);
}
}
for(auto lef:le) q.push((ele){l,mid,lef});
for(auto rig:ri) q.push((ele){mid+1,r,rig});
}
}
int main(){
read(n);read(m);read(k);
int i,t1,t2,t3,tmp;
memset(first,-1,sizeof(first));
for(i=1;i<n;i++){
read(t1);read(t2);
add(t1,t2);
}
dfs(1,0);ST();
for(i=1;i<=m;i++){
read(t1);read(t2);read(t3);
if(dep[t2]<dep[t1]) swap(t1,t2);
tmp=getpre(t1,t2);
if(tmp){
if(dfn[tmp]>1) p[++cntp]=(mat){1,dfn[tmp]-1+1,dfn[t2],las[t2],t3,i};
if(las[tmp]<n) p[++cntp]=(mat){dfn[t2],las[t2]+1,las[tmp]+1,n,t3,i};
}
else{
if(dfn[t2]<dfn[t1]) swap(t1,t2);
p[++cntp]=(mat){dfn[t1],las[t1]+1,dfn[t2],las[t2],t3,i};
}
} sort(p+1,p+cntp+1,cmp); for(i=1;i<=k;i++){
read(t1);read(t2);read(t3);
if(dfn[t1]>dfn[t2]) swap(t1,t2);
f[i]=(fru){dfn[t1],dfn[t2],i,0,t3};
}
solve();
for(i=1;i<=k;i++) print(f[i].ans),el();
flush();
}

[HNOI2015][bzoj4009] 接水果 [整体二分+扫描线]的更多相关文章

  1. BZOJ.4009.[HNOI2015]接水果(整体二分 扫描线)

    LOJ BZOJ 洛谷 又是一个三OJ rank1!=w= \(Description\) (还是感觉,为啥非要出那种题目背景啊=-=直接说不好么) 给定一棵树和一个路径集合(每条路径有一个权值).\ ...

  2. BZOJ 4009: [HNOI2015]接水果 (整体二分+扫描线 树状数组)

    整体二分+扫描线 树状数组 具体做法看这里a CODE #include <cctype> #include <cstdio> #include <cstring> ...

  3. [bzoj4009] [HNOI2015]接水果 整体二分+扫描线+dfs序+树状数组

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

  4. bzoj4009 [HNOI2015]接水果 整体二分+扫描线+树状数组+dfs序

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4009 题解 考虑怎样的情况就会有一个链覆盖另一个链. 设被覆盖的链为 \(a - b\),覆盖 ...

  5. 【BZOJ4009】[HNOI2015]接水果 DFS序+整体二分+扫描线+树状数组

    [BZOJ4009][HNOI2015]接水果 Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果.由于她已经DT FC 了The big black, ...

  6. [BZOJ4009][HNOI2015]接水果(整体二分)

    [HNOI2015]接水果 时间限制:60s      空间限制:512MB 题目描述 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The b ...

  7. BZOJ4009:[HNOI2015]接水果(整体二分版)

    浅谈离线分治算法:https://www.cnblogs.com/AKMer/p/10415556.html 题目传送门:https://lydsy.com/JudgeOnline/problem.p ...

  8. 接水果(fruit)——整体二分+扫描线

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

  9. luogu3242 接水果 (整体二分+树状数组)

    考虑整体二分,问题就变成了每个(水果)路径有多少个满足条件(权值)的(盘子)子路径 考虑一个盘子(a,b)表示两端点(不妨设dfn[a]<dfn[b]),那么他能接到的水果(u,v)一定满足(不 ...

随机推荐

  1. Python 文件访问模式

    f = open('xxx文件', '访问模式') r    以只读方式打开文件(read).文件的指针将会放在文件的开头.默认模式. w   打开一个文件只用于写入(write).如果该文件已存在则 ...

  2. Anaconda下安装 TensorFlow 和 keras 以及连接pycharm

    首先在官网下载Anaconda https://www.anaconda.com/download/ 安装时注意 勾选第一个,增加环境变量 安装好后再windows界面打开Anaconda Promp ...

  3. mysql 命令 小结

    CREATE DATABASE IF NOT EXISTS yourdbname DEFAULT CHARSET utf8 COLLATE utf8_general_ci;创建中文数据库show gl ...

  4. sqlite的sql常用语句(笔记)

    1.复制一张表并重命名 比如已经创建好一个表 表名为"28165" 复制这个表. CREATE TABLE [33150] AS SELECT * FROM [28165] 2.根 ...

  5. 【jQuery】手机验证码倒计时效果

    <ul class="ulist"> <li class="group"> <label class="label&qu ...

  6. PHP获取异常信息

    try { } catch (\Exception $e) { $extra = [ 'code' => $e->getCode(), 'msg' => $e->getMess ...

  7. Linux基础知识与命令1(su passwd)

    一.Linux的基本原则 1.linux由一个个目的单一的小程序组成,我们一般需要组合小程序来完成复杂的任务 2.Linux的一切都是文件(文件类似于一棵树,包括外设,接口) 3.Linux尽量避免捕 ...

  8. caioj:1348: [NOIP普及组2012]质因数分解 C++

    题目描述 已知正整数n是两个不同的质数的乘积,试求出两者中较大的那个质数. 输入样例 21 输出样例 7 输入 输入只有一行,包含一个正整数n. 输出 输出只有一行,包含一个正整数p,即较大的那个质数 ...

  9. ElasticSearch 之 Client

    在使用ElasticSearch的时候,我们需要与Cluster通信,Java版本的API提供了几种方式来构造Client,进而通过Client操作Cluster.   1)使用Node与clusto ...

  10. H2数据库使用

    H2数据库使用 H2数据库介绍 H2的优势: 1.h2采用纯Java编写,因此不受平台的限制. 2.h2只有一个jar文件,十分适合作为嵌入式数据库试用. 3.性能和功能的优势 H2和各数据库特征比较 ...