zoukankan      html  css  js  c++  java
  • P3242 [HNOI2015]接水果 树上莫队+分块

    题意:

    有一颗大小为(n)的树,给定(m)条固定路径,再给定(q)条查询路径,求每条查询路径上第(k)大的固定路径

    范围&性质:(1le n,m,qle 4 imes10^4)

    分析:

    我们将问题拆成两部分,求每条询问路径上有几条固定路径,求一个固定路径集合中第(k)大的路径

    我们发现前一部分可以用树上莫队解决,后一部分可以用分块解决,好像这道题就能做了

    QED.

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	typedef long long ll;
    	const int maxn = 2e6+5;
    	ll n,m,q,cnt=0,idx=0,l,r,sz,num,block,size;
    	ll head[maxn],sum[maxn],line[maxn],bel[maxn],gs[maxn],fa[maxn][25],in[maxn],id[maxn],out[maxn];
    	ll a[maxn],b[maxn],dep[maxn],L[maxn],R[maxn],ans[maxn];
    	bool vis[maxn];
    	vector<ll> v[maxn];
    	
    	struct node
    	{
    		ll l,r,id,k,lca;
    	}Q[maxn];
    	
    	bool cmp1(node a,node b)
    	{
    		return (a.l/block)^(b.l/block)?(a.l<b.l):((a.l/block)&1)?(a.r<b.r):(a.r>b.r);
    	}
    	
    	struct edge
    	{
    		ll to,nxt;
    	}e[maxn<<1];
    	
    	void add(ll u,ll v)
    	{
    		e[++cnt].to=v;
    		e[cnt].nxt=head[u];
    		head[u]=cnt;
    	}
    	
    	void dfs(ll u,ll ff)
    	{
    		fa[u][0]=ff;
    		dep[u]=dep[ff]+1;
    		in[u]=++idx;
    		id[idx]=u;
    		for(ll i=head[u];i;i=e[i].nxt)
    		{
    			ll v=e[i].to;
    			if(v==ff) continue;
    			dfs(v,u);
    		}
    		out[u]=++idx;
    		id[idx]=u;
    	}
    	
    	ll lca(ll x,ll y)
    	{
    		if(dep[x]<dep[y]) swap(x,y);
    		for(ll i=20;i>=0;i--)
    		{
    			if(dep[fa[x][i]]>=dep[y])
    			{
    				x=fa[x][i];
    			}
    		}
    		if(x==y) return x;
    		for(ll i=20;i>=0;i--)
    		{
    			if(fa[x][i]!=fa[y][i])
    			{
    				x=fa[x][i];
    				y=fa[y][i];
    			}
    		}
    		return fa[x][0];
    	}
    	
    	void Insert(ll x)
    	{
    		gs[x]++;
    		sum[bel[x]]++;
    	}
    	
    	void Delete(ll x)
    	{
    		gs[x]--;
    		sum[bel[x]]--;
    	}
    	
    	void add(ll pos)
    	{
    		for(ll i=0;i<(ll)v[pos].size();i++)
    		{
    			line[v[pos][i]]++;
    			if(line[v[pos][i]]==2) Insert(a[v[pos][i]]);
    		}
    	}
    	
    	void del(ll pos)
    	{
    		for(ll i=0;i<(ll)v[pos].size();i++)
    		{
    			line[v[pos][i]]--;
    			if(line[v[pos][i]]==1) Delete(a[v[pos][i]]);
    		}
    	}
    	
    	void move(ll pos)
    	{
    		if(vis[pos]) del(pos);
    		else add(pos);
    		vis[pos]^=1;
    	}
    	
    	ll query(ll k)
    	{
    		ll i,res=0;
    		for(i=1;i<=num;i++)
    		{
    			res+=sum[i];
    			if(res>=k) break;
    		}
    		for(ll j=R[i];j>=L[i];j--)
    		{
    			if(res>k-gs[j]&&res<=k) return b[j];
    			res-=gs[j];
    		}
    	}
    	
    	void work()
    	{
    		ll x,y;
    		scanf("%lld%lld%lld",&n,&m,&q);
    		for(ll i=1;i<n;i++)
    		{
    			scanf("%lld%lld",&x,&y);
    			add(x,y);
    			add(y,x);
    		}
    		for(ll i=1;i<=m;i++)
    		{
    			scanf("%lld%lld",&x,&y);
    			scanf("%lld",&a[i]);b[i]=a[i];
    			v[x].push_back(i);
    			v[y].push_back(i);
    		}
    		sort(b+1,b+m+1);
    		size=unique(b+1,b+m+1)-(b+1);
    		for(ll i=1;i<=m;i++)
    		{
    			a[i]=lower_bound(b+1,b+size+1,a[i])-b;
    		}
    		sz=sqrt(m);
    		num=m/sz;
    		if(m%sz) num++;
    		for(ll i=1;i<=m;i++) L[i]=m+1;
    		for(ll i=1;i<=m;i++)
    		{
    			bel[i]=(i-1)/sz+1;
    			L[bel[i]]=min(L[bel[i]],i);
    			R[bel[i]]=max(R[bel[i]],i);
    		}
    		dfs(1,0);
    		for(ll i=1;i<=18;i++)
    		{
    			for(int j=1;j<=n;j++)
    			{
    				fa[j][i]=fa[fa[j][i-1]][i-1];
    			}
    		}
    		block=pow(idx,2.0/3.0);
    		for(ll i=1;i<=q;i++)
    		{
    			Q[i].id =i;
    			scanf("%lld%lld%lld",&x,&y,&Q[i].k);
    			if(in[x]>in[y]) swap(x,y);
    			ll tmp=lca(x,y);
    			if(tmp==x) Q[i].lca=0,Q[i].l=in[x],Q[i].r=in[y];
    			else Q[i].lca=tmp,Q[i].l=out[x],Q[i].r=in[y];
    		}
    		sort(Q+1,Q+q+1,cmp1);
    		l=1;
    		for(ll i=1;i<=q;i++)
    		{
    			while(l>Q[i].l) move(id[--l]);
    			while(r<Q[i].r) move(id[++r]);
    			while(l<Q[i].l) move(id[l++]);
    			while(r>Q[i].r) move(id[r--]);
    			if(Q[i].lca) move(Q[i].lca);
    			ans[Q[i].id]=query(Q[i].k);
    			if(Q[i].lca) move(Q[i].lca);
    		}
    		for(ll i=1;i<=q;i++)
    		{
    			printf("%lld
    ",ans[i]);
    		}
    	}
    	
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
  • 相关阅读:
    Android获取手机内存和sd卡相关信息
    总结(创建快捷方式等)
    正则是个好东西
    Android自定义AlertDialog
    Eclipse生成author等注释
    day18 io多路复用
    json 模块
    re 模块
    random 模块
    hashlib 模块
  • 原文地址:https://www.cnblogs.com/youth518/p/13710089.html
Copyright © 2011-2022 走看看