列表

详情


NC20114. [HNOI2015]接水果

描述

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

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

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

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

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

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

 

输入描述

第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数。
接下来n-1 行,每行两个数 a、b,表示树上的a和b之间有一条边。树中顶点按1到n标号。
接下来 P 行,每行三个数 a、b、c,表示路径为a到b、权值为c的盘子,其中0 ≤ c ≤ 10^9,a不等于b。
接下来Q行,每行三个数 u、v、k,表示路径为u到v的水果,其中u不等于v,你需要选择第k小的盘子,第k小一定存在。

输出描述

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

示例1

输入:

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

输出:

442139372
333042360
442139372
283254485
283254485
217394434
217394434
217394434
217394434
217394434

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 140ms, 内存消耗: 8680K, 提交时间: 2019-10-29 22:14:00

//It is made by M_sea
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define re register
using namespace std;

inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=200000+10;

//结构体和重载
struct Matrix { int x1,y1,x2,y2,k; } t[N];
struct Fruit { int x,y,k,id; } q[N],lq[N],rq[N];
struct Line { int y1,y2,x,v; } p[N];
bool operator <(Matrix a,Matrix b) { return a.k<b.k; }
bool operator <(Fruit a,Fruit b) { return a.x<b.x; }
bool operator <(Line a,Line b) { return a.x<b.x; }

//邻接表
struct Edge { int v,nxt; } e[N];
int head[N],cnt=0;

inline void addEdge(int u,int v) {
    e[++cnt]=(Edge){v,head[u]},head[u]=cnt;
}

//变量
int n,P,Q;
int f[18][N],dep[N];
int st[N],ed[N],dfs_clock=0,tot=0;
int ans[N];

//树状数组
int c[N];
#define lowbit(x) (x&-x)
inline void add(int x,int y) {
    for (;x<=n;x+=lowbit(x)) c[x]+=y;
}
inline int sum(int x) {
    int ans=0;
    for (;x;x-=lowbit(x)) ans+=c[x];
    return ans;
}

//函数
inline void dfs(int u,int fa) {
    f[0][u]=fa,dep[u]=dep[fa]+1,st[u]=++dfs_clock;
    for (re int i=1;i<=15;++i) f[i][u]=f[i-1][f[i-1][u]];
    for (re int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v; if (v==fa) continue;
        dfs(v,u);
    }
    ed[u]=dfs_clock;
}

inline int LCA(int u,int v,int op) {
    if (dep[u]<dep[v]) swap(u,v);
    for (re int i=15;i>=0;--i)
        if (dep[f[i][u]]>dep[v]) u=f[i][u];
    if (f[0][u]==v) return op?u:v;
    u=f[0][u];
    for (re int i=15;i>=0;--i)
        if (f[i][u]!=f[i][v]) u=f[i][u],v=f[i][v];
    return op?u:f[0][u];
}

inline void solve(int L,int R,int lval,int rval) {
    if (L>R) return;
    if (lval==rval) {
        for (re int i=L;i<=R;++i) ans[q[i].id]=lval;
        return;
    }
    int mid=(lval+rval)>>1,lt=0,rt=0,cnt=0;
    for (re int i=lval;i<=mid;++i) {
        p[++cnt]=(Line){t[i].y1,t[i].y2,t[i].x1,1};
        p[++cnt]=(Line){t[i].y1,t[i].y2,t[i].x2+1,-1};
    }
    sort(p+1,p+cnt+1);
    int pos=1;
    for (re int i=L;i<=R;++i) {
        while (pos<=cnt&&p[pos].x<=q[i].x)
            add(p[pos].y1,p[pos].v),add(p[pos].y2+1,-p[pos].v),++pos;
        int s=sum(q[i].y);
        if (q[i].k<=s) lq[++lt]=q[i];
        else q[i].k-=s,rq[++rt]=q[i];
    }
    for (re int i=1;i<pos;++i)
        add(p[i].y1,-p[i].v),add(p[i].y2+1,p[i].v);
    for (re int i=1;i<=lt;++i) q[L+i-1]=lq[i];
    for (re int i=1;i<=rt;++i) q[L+lt+i-1]=rq[i];
    solve(L,L+lt-1,lval,mid),solve(L+lt,R,mid+1,rval);
}

int main() {
    n=read(),P=read(),Q=read();
    for (re int i=1;i<n;++i) {
        int u=read(),v=read();
        addEdge(u,v),addEdge(v,u);
    }
    dfs(1,0);
    for (re int i=1;i<=P;++i) {
        int u=read(),v=read(),k=read();
        if (st[u]>st[v]) swap(u,v);
        int lca=LCA(u,v,0);
        if (u!=lca) t[++tot]=(Matrix){st[u],st[v],ed[u],ed[v],k};
        else {
            int d=LCA(u,v,1);
            if (st[d]!=1) t[++tot]=(Matrix){1,st[v],st[d]-1,ed[v],k};
            if (ed[d]!=n) t[++tot]=(Matrix){st[v],ed[d]+1,ed[v],n,k};
        }
    }
    for (re int i=1;i<=Q;++i) {
        int u=read(),v=read(),k=read();
        if (st[u]>st[v]) swap(u,v);
        q[i]=(Fruit){st[u],st[v],k,i};
    }
    sort(t+1,t+tot+1); sort(q+1,q+Q+1);
    solve(1,Q,1,tot);
    for (re int i=1;i<=Q;++i) printf("%d\n",t[ans[i]].k);
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 142ms, 内存消耗: 20464K, 提交时间: 2019-03-16 10:37:48

#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<vector>
#define MAXN 200005
#define MAXM 400005
using namespace std;

char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?0:*p1++)
inline int _R(){
	char s=GC;int sign=0,v=0;
	while((s!='-')&&(s>57||s<48))s=GC;
	if(s=='-')s=GC,sign=1;
	for(;s>47&&s<58;s=GC)v=v*10+s-48;
	return sign?-v:v;
}

int N,P,Q,Ans[MAXN];

struct rec{
	int l,r,d,u,v;
	rec(int ll=0,int rr=0,int dd=0,int uu=0,int vv=0){
		l=ll;r=rr;u=uu;d=dd;v=vv;
		if(l>d)swap(l,d),swap(r,u);
		else if(l==d&&r>u)swap(r,u);
	}
}A[MAXN*2];int cnt;

struct node{
	int u,v,k,id;
};

struct line{
	int l,d,u,k,id;
}L[MAXN];
bool operator<(line a,line b){
	return a.l==b.l?a.id<b.id:a.l<b.l;
}

bool cmpv(rec a,rec b){
	return a.v<b.v;
}

bool cmpp(rec a,rec b){
	return a.l==b.l?a.r<b.r:a.l<b.l;
}

int en[MAXM],nex[MAXM],las[MAXN],tot;
void Add(int x,int y){
	en[++tot]=y;
	nex[tot]=las[x];
	las[x]=tot;
}

int fa[MAXN][17],dep[MAXN],In[MAXN],Out[MAXN],VT;
void DFS(int x,int f){
	int i,y;
	In[x]=++VT;
	dep[x]=dep[f]+1;fa[x][0]=f;
	for(i=1;i<17;i++)fa[x][i]=fa[fa[x][i-1]][i-1];
	for(i=las[x];i;i=nex[i]){
		y=en[i];if(y==f)continue;
		DFS(y,x);
	}
	Out[x]=VT;
}

int LCA(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	int d=dep[x]-dep[y],i;
	for(i=0;i<17;i++)if(d>>i&1)x=fa[x][i];
	if(x==y)return x;
	for(i=16;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}

int gf(int x,int d){
	for(int i=0;i<17;i++)if(d>>i&1)x=fa[x][i];
	return x;
}

int C[MAXN];
void Modify(int x,int k){
	for(int i=x;i<=N;i+=(i&-i))C[i]+=k;
}
int GetSum(int x){
	int i,ret=0;
	for(i=x;i;i^=(i&-i))ret+=C[i];
	return ret;
}

vector<node>qry;

void Solve(int l,int r,vector<node>T){
	if(l==r){
		for(int i=0;i<T.size();i++)Ans[T[i].id]=A[l].v;
		return;
	}
	int i,mid=l+r>>1,cnt=0,t;
	vector<node>Q1,Q2;
	for(i=l;i<=mid;i++){
		L[++cnt]=(line){A[i].l,A[i].d,A[i].u,1,0};
		L[++cnt]=(line){A[i].r,A[i].d,A[i].u,-1,N+P+Q};
	}
	for(i=0;i<T.size();i++)L[++cnt]=(line){T[i].u,T[i].v,0,T[i].k,T[i].id};
	sort(L+1,L+cnt+1);
	for(i=1;i<=cnt;i++){
		if(L[i].id>=1&&L[i].id<=Q){
			t=GetSum(L[i].d);
			if(t>=L[i].k)Q1.push_back((node){L[i].l,L[i].d,L[i].k,L[i].id});
			else Q2.push_back((node){L[i].l,L[i].d,L[i].k-t,L[i].id});
		}
		else{
			Modify(L[i].d,L[i].k);
			Modify(L[i].u+1,-L[i].k);
		}
	}
	Solve(l,mid,Q1);
	Solve(mid+1,r,Q2);
}

int main(){
	int i,x,y,a,b,c,d,lca;
	N=_R();P=_R();Q=_R();
	for(i=1;i<N;i++){
		x=_R();y=_R();
		Add(x,y);Add(y,x);
	}
	DFS(1,0);
	for(i=1;i<=P;i++){
		a=_R();b=_R();c=_R();
		lca=LCA(a,b);
		if(lca==a||lca==b){
			if(dep[a]<dep[b])swap(a,b);
			d=gf(a,dep[a]-dep[b]-1);
			A[++cnt]=rec(In[a],Out[a],1,In[d]-1,c);
			if(Out[d]+1<=N)A[++cnt]=rec(In[a],Out[a],Out[d]+1,N,c);
		}
		else A[++cnt]=rec(In[a],Out[a],In[b],Out[b],c);
	}
	sort(A+1,A+cnt+1,cmpv);
	for(i=1;i<=Q;i++){
		x=_R();y=_R();a=_R();
		if(In[x]>In[y])swap(x,y);
		qry.push_back((node){In[x],In[y],a,i});
	}
	Solve(1,cnt,qry);
	for(i=1;i<=Q;i++)printf("%d\n",Ans[i]);
}

上一题