• P4074 [WC2013]糖果公园 树上带修莫队


    题意:

    -> 戳这里查看题面

    分析:

    julao口中的树上带修莫队的板子题

    • 前置芝士: 欧拉序,带修莫队

    这个题拆开来说就是:带修莫队+树上莫队

    1. 带修莫队是莫队的最基本的一种,就是将询问排序后,按时间戳将修改操作增加或减少
    2. 树上莫队有两种写法,分别是按照大小分块按照欧拉序分块,这里介绍用欧拉序分块的写法,通过欧拉序我们可以将树上问题转化为序列问题,因为欧拉序里两个相同的数之间包含ta的子树

    tip:对于树上莫队的欧拉序写法还需要特别注意一下lca的特判,当(lca(x,y) e x|y)时,在欧拉序上是不会出现(lca)的,需要专门计算

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	typedef long long ll;
    	const int maxn = 5e5+5;
    	ll head[maxn],c[maxn],v[maxn],w[maxn],id[maxn],in[maxn],out[maxn],dep[maxn];
    	ll fa[maxn][25],belong[maxn],pre[maxn],cnt[maxn];
    	ll n,m,q,ecnt=0,qcnt=0,block,tim,ans=0;
    	bool vis[maxn];
    	
    	struct edge
    	{
    		ll to,nxt;
    	}e[maxn<<1];
    	
    	struct chan
    	{
    		ll pos,old,now,id;
    	}C[maxn];
    	
    	struct que
    	{
    		ll l,r,val,id,ti;
    	}Q[maxn];
    	
    	bool cmp1(que a,que b)
    	{
    		return belong[a.l]==belong[b.l]?belong[a.r]==belong[b.r]?a.ti<b.ti:belong[a.r]<belong[b.r]:belong[a.l]<belong[b.l];
    	}
    	
    	bool cmp2(que a,que b)
    	{
    		return a.id<b.id;
    	}
    	
    	void add(ll u,ll v)
    	{
    		e[++ecnt].to=v;
    		e[ecnt].nxt=head[u];
    		head[u]=ecnt;
    	}
    	
    	ll idx;
    	void dfs(ll u,ll ff)
    	{
    		fa[u][0]=ff;
    		dep[u]=dep[ff]+1;
    		id[++idx]=u;
    		in[u]=idx;
    		for(ll i=head[u];i;i=e[i].nxt)
    	    {
    	    	ll v=e[i].to;
    	    	if(v==ff) continue;
    	    	dfs(v,u);
    		}
    		id[++idx]=u;
    		out[u]=idx;
    	}
    	
    	void getpre()
    	{
    		for(ll i=1;i<=20;i++)
    		{
    			for(ll j=1;j<=n;j++)
    			{
    				fa[j][i]=fa[fa[j][i-1]][i-1];
    			}
    		}
    	}
    	
    	ll lca(ll x,ll y)
    	{
    		if(dep[x]<dep[y]) swap(x,y);
    		for(int i=20;i>=0;i--)
    		{
    			if(dep[fa[x][i]]>=dep[y])
    			{
    				x=fa[x][i];
    			}
    		}
    		if(x==y) return x;
    		for(int 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 calc(int pos)
    	{
    		if(vis[pos]) ans-=w[cnt[c[pos]]--]*v[c[pos]];
    		else ans+=w[++cnt[c[pos]]]*v[c[pos]];
    		vis[pos]^=1;
    	}
    	
    	void update(int pos,int col)
    	{
    		if(vis[pos])
    		{
    			calc(pos);
    			c[pos]=col;
    			calc(pos);
    		}
    		else c[pos]=col;
    	}
    	
    	void work()
    	{
    		ll a,b,opt;
    		scanf("%lld%lld%lld",&n,&m,&q);
    		block=(ll)pow(n,2.0/3);
    		
    		for(ll i=1;i<=m;i++) scanf("%lld",&v[i]);
    	    for(ll i=1;i<=n;i++) scanf("%lld",&w[i]);
    		for(ll i=1;i<n;i++)
    		{
    			scanf("%lld%lld",&a,&b);
    			add(a,b);
    			add(b,a);
    		}
    		for(ll i=1;i<=n;i++) scanf("%lld",&c[i]),pre[i]=c[i];
    		dfs(1,0);
    		getpre();
    		for(int i=1;i<=idx;i++)
    		{
    			belong[i]=(i-1)/block+1;
    		}
    		for(ll i=1;i<=q;i++)
    		{
    			scanf("%lld%lld%lld",&opt,&a,&b);
    			if(opt==1)
    			{
    				if(in[a]>in[b]) swap(a,b);
    				Q[++qcnt].id=qcnt;
    				Q[qcnt].r=in[b];
    				Q[qcnt].ti=tim;
    				Q[qcnt].l=((lca(a,b)==a)?in[a]:out[a]);
    			}
    			else
    			{
    				C[++tim].pos=a;
    				C[tim].old=pre[a];
    				C[tim].now=b;
    				pre[a]=b;
    			}
    		}
    		sort(Q+1,Q+qcnt+1,cmp1);
    		tim=0;
    		ll l=1,r=0;
    		for(int i=1;i<=qcnt;i++)
    		{
    			while(tim<Q[i].ti)
    			{
    				tim++;
    				update(C[tim].pos,C[tim].now);
    			}
    			while(tim>Q[i].ti)
    			{
    				update(C[tim].pos,C[tim].old);
    				tim--;
    			}
    			while(r<Q[i].r) calc(id[++r]);
    			while(l>Q[i].l) calc(id[--l]);
    			while(l<Q[i].l) calc(id[l++]);
    			while(r>Q[i].r) calc(id[r--]);
    			ll x=id[l],y=id[r],tmp=lca(x,y);
    			if(tmp!=x&&tmp!=y)
    			{
    				calc(tmp);
    				Q[i].val=ans;
    				calc(tmp);
    			}
    			else Q[i].val=ans;
    		}
    		sort(Q+1,Q+qcnt+1,cmp2);
    		for(int i=1;i<=qcnt;i++)
    		{
    			printf("%lld
    ",Q[i].val);
    		}
    	}
    	
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
     } 
    
  • 相关阅读:
    linux进程间通信之消息队列
    本地安装discuz x2.5(论坛站)程序
    缩小IO/CPU瓶颈:linux平台加速编译速度的几种方法
    php mcrypt
    Nginx工作原理和优化、漏洞。
    Linux下两种TCP网络服务器实现方式:循环服务&并发服务
    version `GLIBC_2.14' not found 解决方法.
    Flex Ant自动构建
    函数传指针和传引用
    JEECG 列表行编辑模式下实现文本的xheditor富文本框编辑器
  • 原文地址:https://www.cnblogs.com/youth518/p/13710092.html
Copyright © 2020-2023  润新知