• BZOJ 4009 接水果


    Description

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

    Input

    第一行三个数(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 eq b)
    接下来(Q)行,每行三个数(u,v,k),表示路径为(u)(v)的水果,其中(u eq 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

    (N,P,Q le 40000)

    整体二分。对于区间(l sim r),二分值域(mid),将(le mid)的盘子加入,每个水果的(k)与其路径上存在的盘子数进行比较,若多了该询问往左区间(l sim mid)递归,否则往右区间(mid+1 sim r)递归。
    现在的问题就是如何判定每个水果的(k)与其路径上存在的盘子数的大小关系。考虑每个盘子,覆盖的路径为(a_{i})(b_{i})(dep_{a_{i}} < dep_{b_{i}})),那么这个盘子所贡献的水果只有可能两种情况:
    (1.b_{i})(a_{i})的子树内,那么水果的两个端点(u,v)必须一个(b_{i})的子树内,一个在(a_{i})的子树外(可以包括(a_{i}))。
    (2.)否则,两个点必须一个在(a_{i})的子树内,一个在(b_{i})的子树内。
    看到有子树的东西,马上想到dfs序。由于这个dfs序是一段连续的区间,所以我们可以将盘子根据dfs序抽象成为矩形(情况一上两个不相交的矩形,情况二是一个矩形),将水果抽象成为一个点,每次检验即询问点被多少矩形所覆盖。扫描线+树状数组即可解决。
    注意:矩形必须保证(x)坐标小于(y)坐标。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    
    #define maxn (40010)
    int N,P,Q,side[maxn],next[maxn*2],toit[maxn*2],dep[maxn],tree[maxn];
    int L[maxn],R[maxn],ans[maxn],f[maxn][20],Ts,cnt,tot,have[maxn],sum[maxn];
    struct SCAN
    {
    	int X,Y1,Y2,sign,be;
    	friend inline bool operator <(const SCAN &a,const SCAN &b) { return a.X != b.X?a.X < b.X:a.sign<b.sign; }
    }bac[8*maxn],save[maxn][4];
    
    inline int jump(int a,int step)
    {
    	for (int i = 0;step;step >>= 1,++i) if (step&1) a = f[a][i];
    	return a;
    }
    
    inline int lowbit(int a) { return a&-a; }
    inline void modify(int a,int b) { for (;a <= N;a += lowbit(a)) tree[a] += b; }
    inline int calc(int a) { int ret = 0; for (;a;a -= lowbit(a)) ret += tree[a]; return ret; }
    
    struct NODE
    {
    	int a,b,c,id;
    	friend inline bool operator <(const NODE &x,const NODE &y) { return x.c < y.c; }
    	inline void read(int i) { scanf("%d %d %d",&a,&b,&c); id = i; }
    	inline void update() { if (L[a] > L[b]) swap(a,b); }
    	inline void ins1() { bac[++tot] = (SCAN){L[a],L[b],L[b],0,id}; }
    	inline void ins2() { for (int i = 0;i < have[id];++i) bac[++tot] = save[id][i]; }
    	inline void change()
    	{
    		if (L[b] >= L[a]&&L[b] <= R[a])
    		{
    			int son = jump(b,dep[b]-dep[a]-1);
    			if (L[son] > 1)
    			{
    				save[id][have[id]++] = (SCAN){1,L[b],R[b],-1,id};
    				save[id][have[id]++] = (SCAN){L[son]-1,L[b],R[b],1,id};
    			}
    			if (R[son] < N)
    			{
    				save[id][have[id]++] = (SCAN){L[b],R[son]+1,N,-1,id};
    				save[id][have[id]++] = (SCAN){R[b],R[son]+1,N,1,id};
    			}
    		}
    		else
    		{
    			save[id][have[id]++] = (SCAN){L[a],L[b],R[b],-1,id};
    			save[id][have[id]++] = (SCAN){R[a],L[b],R[b],1,id};
    		}
    	}
    }path[maxn],query[maxn],tmp[maxn];
    
    inline void add(int a,int b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; }
    inline void ins(int a,int b) { add(a,b); add(b,a); }
    
    inline void dfs(int now)
    {
    	L[now] = ++Ts;
    	for (int i = 1;(1 << i) <= dep[now];++i) f[now][i] = f[f[now][i-1]][i-1];
    	for (int i = side[now];i;i = next[i])
    		if (toit[i] != f[now][0])
    			f[toit[i]][0] = now,dep[toit[i]] = dep[now]+1,dfs(toit[i]);
    	R[now] = Ts;
    }
    
    inline void census(int ql,int qr,int pl,int pr,int &ll,int &rr)
    {
    	tot = 0;
    	for (int i = pl;i <= pr;++i) path[i].ins2();
    	for (int i = ql;i <= qr;++i) query[i].ins1();
    	sort(bac+1,bac+tot+1);
    	for (int i = 1;i <= tot;++i)
    	{
    		if (!bac[i].sign) sum[bac[i].be] = calc(bac[i].Y1);
    		else modify(bac[i].Y1,-bac[i].sign),modify(bac[i].Y2+1,bac[i].sign);
    	}
    	for (int i = ql;i <= qr;++i)
    	{
    		if (sum[query[i].id] >= query[i].c) tmp[++ll] = query[i];
    		else query[i].c -= sum[query[i].id],tmp[--rr] = query[i];
    		sum[query[i].id] = 0;
    	}
    	for (int i = ql;i <= qr;++i) query[i] = tmp[i];
    	for (int i = 1;i <= tot;++i)
    		if (bac[i].sign) modify(bac[i].Y1,bac[i].sign),modify(bac[i].Y2+1,-bac[i].sign);
    }
    
    inline void work(int ql,int qr,int pl,int pr)
    {
    	if (ql > qr) return;
    	if (pl == pr)
    	{
    		for (int i = ql;i <= qr;++i) ans[query[i].id] = path[pl].c;
    		return;
    	}
    	int ll = ql-1,rr = qr+1,mid = (pl + pr)>>1;
    	census(ql,qr,pl,mid,ll,rr);
    	work(ql,ll,pl,mid); work(rr,qr,mid+1,pr);
    }
    
    int main()
    {
    	freopen("fruit.in","r",stdin);
    	freopen("fruit.out","w",stdout);
    	scanf("%d %d %d",&N,&P,&Q);
    	for (int i = 1,a,b;i < N;++i) scanf("%d %d",&a,&b),ins(a,b);
    	dfs(1);
    	for (int i = 1;i <= P;++i) path[i].read(i),path[i].update(),path[i].change();
    	sort(path+1,path+P+1);
    	for (int i = 1;i <= Q;++i) query[i].read(i),query[i].update();
    	work(1,Q,1,P);
    	for (int i = 1;i <= Q;++i) printf("%d
    ",ans[i]);
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    html大文件传输技术
    html大文件传输实例解析
    html大文件传输示例
    ckeditor粘贴word图片自动上传功能
    ckeditor不能粘贴word的问题
    ckeditor不能粘贴word的问题如何解决
    vue-ckeditor-word粘贴
    vue中使用ckeditor,支持wps,word,网页粘贴
    富文本编辑器复制word
    富文本编辑器粘贴word
  • 原文地址:https://www.cnblogs.com/mmlz/p/4448719.html
Copyright © 2020-2023  润新知