[HNOI2015]接水果——整体二分
题目大意:
给定一颗树和m条带有权值的路径以及q个路径询问,每次求m条路径中且为给出的路径的子路径的第k小。
思路:
首先考虑怎么判断一条路经是不是一条路径的子路径,假设这条路径在树上拐弯,那么包含它的路径的两个端点要分别在两个子树里面,如果这条路径在树上不拐弯,假设v是深度大的那个,u是深度小的那个,那么包含它的路径要有一个端点在v的子树内,另外一个端点在u连接v的那个儿子的子树外。
于是上面的条件都可以用dfs序来判定,把每一条路径表示成一个二维平面上的点(u,v),每一个子路径代表的范围可以变成一个或者两个矩形,一条路径包含另外一条路径当且仅当这条路径在子路径所表示的矩形内。
于是树上的问题变成了平面上的问题,考虑整体二分,每次check变成了计算包含一个点的矩形的数量,直接扫描线即可计算即可。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define MREP(i,x) for(int i=beg[x],v;v=to[i],i;i=las[i])
#define debug(x) cout<<#x<<"="<<x<<endl
#define fi first
#define se second
#define mk make_pair
#define pb push_back
#define y1 wtcl
typedef long long ll;
using namespace std;
void File(){
freopen("luogu3242.in","r",stdin);
freopen("luogu3242.out","w",stdout);
}
template<typename T>void read(T &_){
T __=0,mul=1; char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')mul=-1;
ch=getchar();
}
while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
_=__*mul;
}
const int maxn=40000+10;
int n,m,q,b[maxn],tot,cnt,ans[maxn],st[maxn][21],Log[maxn],dep[maxn];
int L[maxn],cnt_dfn,R[maxn],sz[maxn];
int beg[maxn],to[maxn<<1],las[maxn<<1],cnte=1;
void add(int u,int v){
las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v;
las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u;
}
void dfs_init(int u,int f){
sz[u]=1;
st[u][0]=f;
dep[u]=dep[f]+1;
L[u]=++cnt_dfn;
MREP(i,u)if(v!=f){
dfs_init(v,u);
sz[u]+=sz[v];
}
R[u]=L[u]+sz[u]-1;
}
struct Query{
int x,y,y1,y2,val,id,ty;
//ty=0 fruit
//ty=1 add to the BIT
//ty=-1 erase from the BIT
bool operator < (const Query & tt) const {
if(x!=tt.x)return x<tt.x;
return abs(ty)>abs(tt.ty);
}
}qu[maxn<<3],t1[maxn<<3],t2[maxn<<3];
int find(int x,int y){
DREP(i,Log[dep[x]-dep[y]],0)
if(dep[st[x][i]]>dep[y])
x=st[x][i];
return x;
}
void init(){
read(n),read(m),read(q);
REP(i,2,n)Log[i]=Log[i/2]+1;
int u,v,val;
REP(i,1,n-1)read(u),read(v),add(u,v);
dfs_init(1,0);
REP(j,1,20)REP(i,1,n)
if((1<<j)<=dep[i]-1)
st[i][j]=st[st[i][j-1]][j-1];
REP(i,1,m){
read(u),read(v),read(val);
b[++tot]=val;
if(L[u]>L[v])swap(u,v);//L[u]<L[v]
if(R[u]<L[v]){
qu[++cnt]=(Query){L[u],0,L[v],R[v],val,0,1};
qu[++cnt]=(Query){R[u]+1,0,L[v],R[v],val,0,-1};
}
else{
u=find(v,u);
qu[++cnt]=(Query){1,0,L[v],R[v],val,0,1};
qu[++cnt]=(Query){L[u],0,L[v],R[v],val,0,-1};
qu[++cnt]=(Query){L[v],0,R[u]+1,n,val,0,1};
qu[++cnt]=(Query){R[v]+1,0,R[u]+1,n,val,0,-1};
}
}
sort(b+1,b+tot+1);
tot=unique(b+1,b+tot+1)-b-1;
REP(i,1,cnt)qu[i].val=lower_bound(b+1,b+tot+1,qu[i].val)-b;
REP(i,1,q){
read(u),read(v),read(val);
if(L[u]>L[v])swap(u,v);
//cout<<L[u]<<" "<<L[v]<<endl;
qu[++cnt]=(Query){L[u],L[v],0,0,val,i,0};
}
sort(qu+1,qu+cnt+1);
//REP(i,1,cnt)printf("%d %d %d %d\n",qu[i].x,qu[i].y1,qu[i].y2,qu[i].ty);
}
struct BIT{
int sum[maxn];
int lowbit(int x){return x&(-x);}
void add(int p,int x){for(;p<=n;p+=lowbit(p))sum[p]+=x;}
int query(int p){int ret=0;for(;p>=1;p-=lowbit(p))ret+=sum[p];return ret;}
}T;
void solve(int ql,int qr,int l,int r){
if(ql>qr || l>r)return;
if(l==r){REP(i,ql,qr)if(!qu[i].ty)ans[qu[i].id]=b[l];return;}
int c1=0,c2=0,mid=(l+r)>>1;
REP(i,ql,qr)if(qu[i].ty){
if(qu[i].val<=mid)t1[++c1]=qu[i];
else t2[++c2]=qu[i];
if(qu[i].val<=mid){
T.add(qu[i].y1,qu[i].ty);
T.add(qu[i].y2+1,-qu[i].ty);
}
//printf("%d %d %d %d\n",qu[i].x,qu[i].y1,qu[i].y2,qu[i].ty);
}
else{
int sum=T.query(qu[i].y);
//printf("%d %d %d\n",qu[i].x,qu[i].y,sum);
if(qu[i].val<=sum)t1[++c1]=qu[i];
else t2[++c2]=qu[i],t2[c2].val-=sum;
}
REP(i,1,c1)if(t1[i].ty){
T.add(t1[i].y1,-t1[i].ty);
T.add(t1[i].y2+1,t1[i].ty);
}
REP(i,1,c1)qu[ql+i-1]=t1[i];
REP(i,1,c2)qu[ql+i+c1-1]=t2[i];
solve(ql,ql+c1-1,l,mid);
solve(ql+c1,qr,mid+1,r);
}
int main(){
File();
init();
solve(1,cnt,1,tot);
REP(i,1,q)printf("%d\n",ans[i]);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· ASP.NET Core - 日志记录系统(二)
· .NET 依赖注入中的 Captive Dependency
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 终于决定:把自己家的能源管理系统开源了!
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(一):从.NET IoT入
· C#实现 Winform 程序在系统托盘显示图标 & 开机自启动
· ASP.NET Core - 日志记录系统(二)
· 实现windows下简单的自动化窗口管理