• bzoj4009: [HNOI2015]接水果


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4009

    思路:先给定一些路径,每个路径有一个权值。

    题目要求的是对于一个路径,它的子路径中权值第k大的是多少


    首先我们观察一个盘子(u,v),它能接到哪些水果呢?

    分情况:如果u!=lca(u,v)

    那么水果的两端点(a,b)就在盘子两端点的子树中

    用dfs序来表示,就是dfn[u]<=a<=last[u],dfn[v]<=b<=last[v]

    last[i]表示i的子树的最大 dfn

    如果u==lca(u,v)

    这时稍微有一些区别,w表示u的儿子且是v的祖先的点,注意不是u

    那么b还是在v子树中,a在除了w子树之外的所有点中

    dfn[v]<=b<=last[v],1<=a<=dfn[w]-1||last[w]+1<=a<=n


    这时,盘子就成了一个或两个矩形,水果就是点

    问题就是求覆盖一个点的矩形中权值第k大的权值是多少》

    扫描线+整体二分就可以了

    我们先将矩形按权值从小到大排序

    然后对于一个点,如果[l,mid]中能覆盖这个点的矩形数不小于k,则说明答案在[l,mid]中

    否则在[mid+1,r],同时k减去覆盖的矩形数


    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=80010,maxk=18;
    using namespace std;
    int n,m,q,cnt,fa[maxn][maxk],dfn[maxn],tim,last[maxn],dep[maxn],ans[maxn],sum[maxn];
    int pre[maxn],now[maxn],son[maxn],tot;
    struct Plate{int xd,xu,yd,yu,v;}plate[maxn];
    struct Event{int x,yd,yu,v,id;}event[maxn];
    struct Poi{int x,y,k,id;}poi[maxn],tmp1[maxn],tmp2[maxn];
    bool operator <(Plate a,Plate b){return a.v<b.v;}
    bool operator <(Event a,Event b){return a.x==b.x?a.id<b.id:a.x<b.x;}
    void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
    
    struct Bit{
    	int val[maxn];
    	void modify(int l,int r,int v){
    		for (int i=l;i<=n;i+=(i&(-i))) val[i]+=v;
    		for (int i=r+1;i<=n;i+=(i&(-i))) val[i]-=v;
    	}
    	int query(int x){int res=0;for (;x;x-=(x&(-x))) res+=val[x];return res;}
    }T;
    
    void dfs(int x){
    	dfn[x]=++tim;
    	for (int i=0;fa[x][i];i++) fa[x][i+1]=fa[fa[x][i]][i];
    	for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x][0])
    		fa[son[y]][0]=x,dep[son[y]]=dep[x]+1,dfs(son[y]);
    	last[x]=tim;
    }
    int jump(int a,int h){for (int i=16;h;i--) if (h>=(1<<i)) h-=(1<<i),a=fa[a][i];return a;}
    int lca(int a,int b){
    	if (dep[a]<dep[b]) swap(a,b);
    	a=jump(a,dep[a]-dep[b]);
    	if (a==b) return a;
    	for (int i=16;i>=0;i--) if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
    	return fa[a][0];
    }
    
    void solve(int l,int r,int st,int ed){
    	if (st>ed) return; 
    	if (l==r){
    		for (int i=st;i<=ed;i++) ans[poi[i].id]=plate[l].v;
    		return;
    	}
    	int mid=(l+r)>>1,siz=0;
    	for (int i=l;i<=mid;i++){
    		event[++siz]=(Event){plate[i].xd,plate[i].yd,plate[i].yu,1,0};
    		event[++siz]=(Event){plate[i].xu,plate[i].yd,plate[i].yu,-1,n+1};
    	}
    	for (int i=st;i<=ed;i++) event[++siz]=(Event){poi[i].x,poi[i].y,0,0,i};
    	sort(event+1,event+1+siz);
    	for (int i=1;i<=siz;i++) 
    		if (st<=event[i].id&&event[i].id<=ed) sum[event[i].id]=T.query(event[i].yd);
    		else T.modify(event[i].yd,event[i].yu,event[i].v);
    	int a=0,b=0;
    	for (int i=st;i<=ed;i++) 
    		if (sum[i]>=poi[i].k) tmp1[++a]=poi[i];
    		else tmp2[++b]=(Poi){poi[i].x,poi[i].y,poi[i].k-sum[i],poi[i].id};
    	for (int i=st;i<=st+a-1;i++) poi[i]=tmp1[i-st+1];
    	for (int i=st+a;i<=ed;i++) poi[i]=tmp2[i-st-a+1];
    	solve(l,mid,st,st+a-1),solve(mid+1,r,st+a,ed);
    }
    
    int main(){
    	scanf("%d%d%d",&n,&m,&q);
    	for (int i=1,a,b;i<n;i++) scanf("%d%d",&a,&b),add(a,b),add(b,a);
    	dfs(1);
    	for (int i=1,a,b,c,u;i<=m;i++){
    		scanf("%d%d%d",&a,&b,&c);u=lca(a,b);
    		if (dfn[a]>dfn[b]) swap(a,b);
    		if (u!=a) plate[++cnt]=(Plate){dfn[a],last[a],dfn[b],last[b],c};
    		else{
    			int w=jump(b,dep[b]-dep[a]-1);
    			plate[++cnt]=(Plate){1,dfn[w]-1,dfn[b],last[b],c};
    			if (last[w]<n) plate[++cnt]=(Plate){dfn[b],last[b],last[w]+1,n,c};
    		}
    	}
    	sort(plate+1,plate+1+cnt);
    	for (int i=1,a,b,k;i<=q;i++){
    		scanf("%d%d%d",&a,&b,&k);
    		if (dfn[a]>dfn[b]) swap(a,b);
    		poi[i]=(Poi){dfn[a],dfn[b],k,i};
    	}
    	solve(1,cnt,1,q);
    	for (int i=1;i<=q;i++) printf("%d
    ",ans[i]);
    	return 0;
    }




  • 相关阅读:
    1002 写出这个数
    1001 害死人不偿命的(3n+1)猜想
    Graph I
    Tree
    进程通信
    管道
    fork函数
    Priority Queue
    Search
    游戏 slider
  • 原文地址:https://www.cnblogs.com/thythy/p/5493497.html
Copyright © 2020-2023  润新知