• BZOJ4009:[HNOI2015]接水果


    Description

    风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更加难的版本。首先有一个地图,是一棵由 n 个顶点、n-1 条边组成的树(例如图 1给出的树包含 8 个顶点、7 条边)。这颗树上有 P 个盘子,每个盘子实际上是一条路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 i 个盘子就是顶点aiai到顶点bibi的路径(由于是树,所以从aiai到bibi 的路径是唯一的), 权值为cici。接下来依次会有Q个水果掉下来,每个水果本质上也是一条路径,第i 个水果是从顶点 uiui 到顶点vivi 的路径。
    幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如 图1中从 3到7 的路径是从1到8的路径的子路径)。
    这里规定:从a 到b的路径与从b到 a的路径是同一条路径。当然为了提高难度,对于第 i 个水果,你需要选择能接住它的所有盘子中,权值第 kiki 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?
    Pic

    Input

    第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数。
    接下来n-1 行,每行两个数 a、b,表示树上的a和b 之间有一条边。树中顶点按1到 n标号。
    接下来 P 行,每行三个数 a、b、c,表示路径为 a 到 b、权值为 c 的盘子,其中0≤c≤109109,a不等于b。
    接下来Q行,每行三个数 u、v、k,表示路径为 u到 v的水果,其中 u不等于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

    Pic

    思路{

      BZOJ上这个题被卡评测了,结果改成了权限题。。。。。。。。只好到WG的OJ上写。。。。。。

      首先不考虑路径的话是区间K大的问题,考虑使用整体二分。

      统计在答案区间内的覆盖的盘子数量,

      比较每次询问的K值大小判断丢入左答案区间还是右答案区间。

      (大于K丢入右区间,小于K丢入左区间:ps:还要统计贡献!)。

      这样就解决了答案查询问题。关键是怎么搞出所覆盖的盘子数呢??????

      我们不妨分类讨论:

      ①一个盘子左右端点a,b其中一个为LCA时:

      水果一端一定在深度较深的盘子端点的子树中,另一端在LCA外。

      ②a,b均不为LCA时:水果两端都在两端盘子的子树中。

      具体用数量关系表示的话,我们考虑用DFS序。

      设DFN[i]为i的dfs序,LAST[i]为以i为根的子树的DFS序的最大值.

      对于①:水果两端u,v,满足:DFN[b]<=DFN[v]<=LAST[b],

      (1<=DFN[u]<=DFN[w]-1)或(LAST[w]+1<=DFN[u]<=n)

      对于②:水果两端u,v满足:DFN[a]<=DFN[u]<=LAST[a],DFN[b]<=DFN[v]<=LAST[b].

      把这些盘子,水果分别抽象成一个个矩形,点:问题转化成求点被多少矩形覆盖!

      然后就可以扫描线算法解决查询问题了!

    }

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <queue>
    #define inf (1<<30)
    #define il inline
    #define RG register
    #define LL long long
    #define lowbit(o) o & (-o)
    #define N 40001
    using namespace std;
    struct ed{int nxt,to;}e[N*2];int head[N],tot;
    int id[N],top[N],BL[N],sz[N],fa[N],deep[N],hson[N],w[N];
    int n,P,Q,idn;
    inline int read() {
    	int x=0;
    	char ch=getchar();
    	while(ch<'0'||ch>'9') ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return x;
    }
    il void add(RG int u,RG int v){e[tot].nxt=head[u];e[tot].to=v;head[u]=tot++;}
    il void ADD(RG int u,RG int v){add(u,v),add(v,u);}
    il void dfs1(RG int u,RG int faa){
    	deep[u]=deep[faa]+1,sz[u]=1;fa[u]=faa;
    	for(RG int i=head[u];i!=-1;i=e[i].nxt)if(e[i].to!=faa){
    			RG int v=e[i].to;dfs1(v,u);
    			sz[u]+=sz[v];if(sz[hson[u]]<sz[v])hson[u]=v;
    		}
    }
    il void dfs2(RG int u,RG int toop){top[u]=toop;
    	id[u]=++idn;BL[idn]=u;if(hson[u])dfs2(hson[u],toop);
    	for(RG int i=head[u];i!=-1;i=e[i].nxt)
    		if(e[i].to!=fa[u]&&e[i].to!=hson[u])
    			dfs2(e[i].to,e[i].to);w[u]=idn;
    }
    il int LCA(RG int x,RG int y){
    	while(top[x]!=top[y]){
    		if(deep[top[x]]<deep[top[y]])swap(x,y);
    		x=fa[top[x]];
    	}if(deep[x]>deep[y])swap(x,y);
    	return x;
    }
    il int gogogo(int x,int y){RG int ll=0;
    	while(top[x]!=top[y]){
    		if(deep[top[x]]<deep[top[y]])swap(x,y);
    		ll=top[x],x=fa[top[x]];
    	}if(deep[x]>deep[y])swap(x,y);
    	return x==y?ll:BL[id[x]+1];
    }
    struct matrix{
    	int x,xx,y,yy,k;
    	matrix() {}
    	matrix(int X,int XX,int Y,int YY,int K):x(X),xx(XX),y(Y),yy(YY),k(K) {}
    }p[N*2];int cnt;
    struct node{
    	int x,y,k,id;
    	node() {}
    	node(int _x,int _y,int _k,int i):x(_x),y(_y),k(_k),id(i) {}
    }ff[N],quer[N],quel[N];
    int tree[N],ans[N];
    il void Add(int x,int y){for(RG int i=x;i<=n;i+=lowbit(i))tree[i]+=y;}
    int Query(int x){int s=0;for(RG int i=x;i;i-=lowbit(i))s+=tree[i];return s;}
    il bool comp(const matrix & a,const matrix & b){return a.k<b.k;}
    struct ha{
    	int x,y,yy,v,kind;
    	ha() {}
    	ha(int a,int b,int c,int d,int e):x(a),y(b),yy(c),v(d),kind(e) {}
    }que[N*3];int sum[N];
    il bool Comp(const ha & a,const ha & b){return a.x==b.x?a.kind<b.kind:a.x<b.x;}
    il void solve(RG int h,RG int t,RG int l,RG int r){
    	if(t<h)return;
    	if(l==r){
    		for(int i=h;i<=t;++i)ans[ff[i].id]=p[l].k;
    		return;
    	}RG int mid=(l+r)>>1;int ss=0;
    	for(RG int i=l;i<=mid;++i){
    		que[++ss]=ha(p[i].x,p[i].y,p[i].yy,1,0);
    		que[++ss]=ha(p[i].xx,p[i].y,p[i].yy,-1,n+1);
    	}for(RG int i=h;i<=t;++i)
    		 que[++ss]=ha(ff[i].x,ff[i].y,0,0,i);
    	sort(que+1,que+ss+1,Comp);memset(tree,0,sizeof(tree));
    	for(RG int i=1;i<=ss;++i)
    		if(que[i].kind>=h&&que[i].kind<=t)
    			sum[que[i].kind]=Query(que[i].y);
    		else Add(que[i].y,que[i].v),Add(que[i].yy+1,-que[i].v);
    	RG int L=0,R=0;
    	for(RG int i=h;i<=t;++i){
    		if(sum[i]>=ff[i].k)quel[++L]=ff[i];
    		else quer[++R]=ff[i],quer[R].k-=sum[i];
    	}for(RG int i=1;i<=L;++i)ff[i+h-1]=quel[i];
    	for(RG int i=1;i<=R;++i)ff[L+h+i-1]=quer[i];
    	solve(h,h+L-1,l,mid);solve(h+L,t,mid+1,r);
    }
    int main(){
    	memset(head,-1,sizeof(head));
    	n=read(),P=read(),Q=read();int u,v;
    	for(RG int i=1;i<n;++i)u=read(),v=read(),ADD(u,v);
    	dfs1(1,1),dfs2(1,1);
    	for(RG int i=1;i<=P;++i){
    		RG int a,b,c;a=read(),b=read(),c=read();
    		RG int lca=LCA(a,b);if(id[a]>id[b])swap(a,b);
    		if(lca==a){RG int mm=gogogo(a,b);
    			if(id[mm]>1)p[++cnt]=matrix(1,id[mm]-1,id[b],w[b],c);
    			if(w[mm]+1<=n)p[++cnt]=matrix(id[b],w[b],w[mm]+1,n,c);
    		}
    		else p[++cnt]=matrix(id[a],w[a],id[b],w[b],c);
    	}
    	for(RG int i=1;i<=Q;++i){
    		RG int u,v,k;u=read(),v=read(),k=read();
    		if(id[u]>id[v])swap(u,v);
    		ff[i]=node(id[u],id[v],k,i);
    	}sort(p+1,p+cnt+1,comp);solve(1,Q,1,cnt);
    	for(RG int i=1;i<=Q;++i)cout<<ans[i]<<"
    ";
        return 0;
    }
    
  • 相关阅读:
    python 时间差计算
    NET Framework 4.5新特性 (一) 数据库的连接加密保护。
    某表含有N个字段超精简模糊查询方法
    清空javascript数组数据
    IIS无法连接LocalDb,怎么办?
    jquery 模糊查询对象属性
    解释杨中科随机数为什么会骗人?
    前端Js传递数组至服务器端
    javascript获取客户端默认打印机
    水晶报表注意的问题
  • 原文地址:https://www.cnblogs.com/zzmmm/p/7170723.html
Copyright © 2020-2023  润新知