zoukankan      html  css  js  c++  java
  • 【BZOJ4538】网络(HNOI2016)-整体二分+树上差分+树状数组

    测试地址:网络
    做法: 本题需要用到整体二分+树上差分+树状数组。
    各位大佬想的都是用一些树链剖分+线段树套堆这种诡异操作,O(mlog3n)O(mlog^3n)卡进去的,然而像我这种常数爆大选手根本不敢写…于是发现还有22loglog的方法,还是挺神的。
    考虑只有一个询问的时候,二分答案,每次二分一个midmid,要知道这个询问的答案是不是大于midmid,只要把前面那些大于midmid的修改计算一下,看到这个询问的时刻时,是不是所有存在的路径都过这个点,如果不是就说明这个询问答案大于midmid,否则相反。
    我们发现涉及到的操作和询问都随着二分的答案区间变化,于是很自然地想到整体二分。于是在判定的时候,用树上差分转化成单点修改子树询问,拍到DFS序上用树状数组维护即可,时间复杂度为O(mlognlogMAX)O(mlog nlog MAX)MAXMAX为最大的答案),可以通过此题。
    …然而现实非常骨感,如果每次用到LCA都倍增算一次的话,就会被卡爆,然而Tarjan又难写,为原已近200行的代码又贡献几十行,但我们发现要求的都是询问中路径的LCA,所以一开始处理好就可以卡进去了。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,first[100010]={0},tot=0;
    int dep[100010]={0},fa[100010][20]={0},in[100010],out[100010],tim=0;
    int LCA[200010],id[200010],tmpl[200010],tmpr[200010];
    int ans[200010]={0},sum[100010]={0},cnt;
    struct edge
    {
    	int v,next;
    }e[200010];
    struct oper
    {
    	int op,a,b,v;
    }q[200010];
    
    int read()
    {
    	char c;
    	int s=0;
    	c=getchar();
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') s=s*10+c-'0',c=getchar();
    	return s;
    }
    
    void insert(int a,int b)
    {
    	e[++tot].v=b;
    	e[tot].next=first[a];
    	first[a]=tot;
    }
    
    void dfs(int v)
    {
    	in[v]=++tim;
    	for(int i=first[v];i;i=e[i].next)
    		if (e[i].v!=fa[v][0])
    		{
    			dep[e[i].v]=dep[v]+1;
    			fa[e[i].v][0]=v;
    			dfs(e[i].v);
    		}
    	out[v]=tim;
    }
    
    int lowbit(int x)
    {
    	return x&(-x);
    }
    
    void add(int x,int d)
    {
    	for(int i=x;i<=n;i+=lowbit(i))
    		sum[i]+=d;
    }
    
    int calc_sum(int x)
    {
    	int ans=0;
    	for(int i=x;i;i-=lowbit(i))
    		ans+=sum[i];
    	return ans;
    }
    
    int lca(int a,int b)
    {
    	if (dep[a]<dep[b]) swap(a,b);
    	for(int i=17;i>=0;i--)
    		if (dep[fa[a][i]]>=dep[b])
    			a=fa[a][i];
    	if (a==b) return a;
    	for(int i=17;i>=0;i--)
    		if (fa[a][i]!=fa[b][i])
    			a=fa[a][i],b=fa[b][i];
    	return fa[a][0];
    }
    
    void modify(int x,int d)
    {
    	int g=LCA[x],a=q[x].a,b=q[x].b;
    	add(in[a],d),add(in[b],d),add(in[g],-d);
    	if (fa[g][0]) add(in[fa[g][0]],-d);
    }
    
    void solve(int l,int r,int ql,int qr)
    {
    	if (ql>qr) return;
    	if (l==r)
    	{
    		if (l==0)
    		{
    			cnt=0;
    			for(int i=ql;i<=qr;i++)
    			{
    				if (q[id[i]].op==0) cnt++,modify(id[i],1);
    				if (q[id[i]].op==1) cnt--,modify(id[i],-1);
    				if (q[id[i]].op==2)
    				{
    					int now=calc_sum(out[q[id[i]].a])-calc_sum(in[q[id[i]].a]-1);
    					if (now<cnt) ans[id[i]]=0;
    					else ans[id[i]]=-1;
    				}
    			}
    			for(int i=ql;i<=qr;i++)
    			{
    				if (q[id[i]].op==0) modify(id[i],-1);
    				if (q[id[i]].op==1) modify(id[i],1);
    			}
    		}
    		else
    		{
    			for(int i=ql;i<=qr;i++)
    				if (q[id[i]].op==2) ans[id[i]]=l;
    		}
    		return;
    	}
    	
    	int mid=(l+r)>>1,tl=0,tr=0;
    	cnt=0;
    	for(int i=ql;i<=qr;i++)
    	{
    		if (q[id[i]].op==0)
    		{
    			if (q[id[i]].v>mid)
    				cnt++,modify(id[i],1),tmpr[++tr]=id[i];
    			else tmpl[++tl]=id[i];
    		}
    		if (q[id[i]].op==1)
    		{
    			if (q[id[i]].v>mid)
    				cnt--,modify(id[i],-1),tmpr[++tr]=id[i];
    			else tmpl[++tl]=id[i];
    		}
    		if (q[id[i]].op==2)
    		{
    			int now=calc_sum(out[q[id[i]].a])-calc_sum(in[q[id[i]].a]-1);
    			if (now<cnt) tmpr[++tr]=id[i];
    			else tmpl[++tl]=id[i];
    		}
    	}
    	for(int i=ql;i<=qr;i++)
    	{
    		if (q[id[i]].op==0&&q[id[i]].v>mid) modify(id[i],-1);
    		if (q[id[i]].op==1&&q[id[i]].v>mid) modify(id[i],1);
    	}
    	
    	for(int i=1;i<=tl;i++) id[ql+i-1]=tmpl[i];
    	for(int i=1;i<=tr;i++) id[ql+tl+i-1]=tmpr[i];
    	solve(l,mid,ql,ql+tl-1);
    	solve(mid+1,r,ql+tl,qr);
    }
    
    int main()
    {
    	n=read(),m=read();
    	for(int i=1;i<n;i++)
    	{
    		int a,b;
    		a=read(),b=read();
    		insert(a,b),insert(b,a);
    	}
    	dep[0]=-1;
    	dfs(1);
    	for(int i=1;i<=17;i++)
    		for(int j=1;j<=n;j++)
    			fa[j][i]=fa[fa[j][i-1]][i-1];
    	int mxv=0;
    	for(int i=1;i<=m;i++)
    	{
    		q[i].op=read();
    		id[i]=i;
    		if (q[i].op==0)
    		{
    			q[i].a=read(),q[i].b=read(),q[i].v=read();
    			mxv=max(mxv,q[i].v);
    			LCA[i]=lca(q[i].a,q[i].b);
    		}
    		if (q[i].op==1)
    		{
    			int t;
    			t=read();
    			q[i].a=q[t].a,q[i].b=q[t].b,q[i].v=q[t].v;
    			LCA[i]=LCA[t];
    		}
    		if (q[i].op==2)
    			q[i].a=read();
    	}
    	
    	solve(0,mxv,1,m);
    	for(int i=1;i<=m;i++)
    		if (q[i].op==2) printf("%d
    ",ans[i]);
    	
    	return 0;
    }
    
  • 相关阅读:
    C# Socket UDP 案例
    精通MVC 3 框架Controller Extensibility
    python一些DEMO总结
    影响ASP.NET程序性能的因素
    Django实战
    EF 4.3 CodeBased 数据迁移演练
    jQuery Gallery Plugin在Asp.Net中使用
    Action Func委托+异步委托
    使用CGO封装Windows API
    每日一例,练就编程高手
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793259.html
Copyright © 2011-2022 走看看