zoukankan      html  css  js  c++  java
  • [WC2013]糖果公园

    题目

    总算知道欧拉序和树上莫队是个什么东西了

    看到这个计算贡献的方式不禁想到了莫队

    带修莫队非常(naive)就是多加一维时间

    来讲讲树上莫队

    如果我们需要子树莫队的话,我们可以直接用(dfs)序把子树转化成一段区间

    但是树上的一条路径显然不是很方便这样做了

    于是我们考虑使用欧拉序

    欧拉序就是在(dfs)进入一个点的时候给它一个编号,记做(st_x),离开这个点的时候又给它一个编号,记做(ed_x)

    这样就得到了一个长度为(2n)的括号序列

    对于一条路径((x,y)),我们强行使得(st_x<st_y)

    如果满足(lca(x,y)=x),那么对应的就是区间就是([st_x,st_y]),但是我们只计算这里面出现了一次的点,出现了两次或(0)次的点不在这条路径上

    如果没有满足(x)(y)的祖先,对应的区间就是([ed_x,st_y]),这样就会发现(lca)(x)路径上的点只有(ed)出现在了这个区间里,(lca)(y)的路径上的点只有(st)出现在这个区间里,但是我们还需要特判一下(lca)

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define re register
    #define LL long long
    const int maxn=100005;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct E{int v,nxt;}e[maxn<<1];
    struct Ask{int l,r,o,rk,t;}q[maxn];
    int head[maxn],son[maxn],sum[maxn],deep[maxn],col[maxn];
    int ed[maxn],st[maxn],dfn[maxn<<1],top[maxn],fa[maxn],w[maxn];
    int pos[maxn],val[maxn],id[maxn<<1],tmp[maxn],tax[maxn],a[maxn];
    int n,m,num,sz,tot,cnt,__,Q;
    LL ans,Ans[maxn];
    inline void add(int x,int y) {
    	e[++num].v=y;e[num].nxt=head[x];head[x]=num;
    }
    void dfs1(int x) {
    	sum[x]=1;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(deep[e[i].v]) continue;
    		deep[e[i].v]=deep[x]+1,fa[e[i].v]=x;
    		dfs1(e[i].v),sum[x]+=sum[e[i].v];
    		if(sum[e[i].v]>sum[son[x]]) son[x]=e[i].v;
    	}
    }
    void dfs2(int x,int topf) {
    	top[x]=topf,st[x]=++__,dfn[__]=x;
    	if(son[x]) dfs2(son[x],topf);
    	for(re int i=head[x];i;i=e[i].nxt)
    	if(!top[e[i].v]) dfs2(e[i].v,e[i].v);
    	ed[x]=++__,dfn[__]=x;
    }
    inline int LCA(int x,int y) {
    	while(top[x]!=top[y]) {
    		if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
    		x=fa[top[x]];
    	}
    	if(deep[x]<deep[y]) return x;return y;
    }
    inline int cmp(Ask A,Ask B) {
    	if(id[A.l]!=id[B.l]) return A.l<B.l;
    	if(id[A.r]!=id[B.r]) return A.r<B.r;
    	return A.t<B.t;
    }
    inline void Add(int x) {
    	tmp[x]++;ans+=1ll*w[tmp[x]]*a[x];
    }
    inline void Del(int x) {
    	ans-=1ll*w[tmp[x]]*a[x];tmp[x]--;
    }
    inline void add(int x) {
    	if(tax[dfn[x]]==0) Add(col[dfn[x]]);
    	if(tax[dfn[x]]==1) Del(col[dfn[x]]);
    	tax[dfn[x]]++;
    }
    inline void del(int x) {
    	tax[dfn[x]]--;
    	if(tax[dfn[x]]==0) Del(col[dfn[x]]);
    	if(tax[dfn[x]]==1) Add(col[dfn[x]]);
    }
    inline int check(int x,int l,int r) {
    	if(st[x]>=l&&st[x]<=r&&ed[x]>=l&&ed[x]<=r) return 0;
    	if(st[x]>=l&&st[x]<=r) return 1;
    	if(ed[x]>=l&&ed[x]<=r) return 1;
    	return 0;
    }
    inline void change(int now,int i) {
    	if(check(pos[now],q[i].l,q[i].r)) {
    		Del(col[pos[now]]);
    		Add(val[now]);
    	}
    	std::swap(col[pos[now]],val[now]);
    }
    int main() {
    	n=read(),m=read(),Q=read();
    	for(re int i=1;i<=m;i++) a[i]=read();
    	for(re int i=1;i<=n;i++) w[i]=read();
    	for(re int x,y,i=1;i<n;i++) 
    		x=read(),y=read(),add(x,y),add(y,x);
    	deep[1]=1,dfs1(1),dfs2(1,1);
    	for(re int i=1;i<=n;i++) col[i]=read();
    	for(re int opt,x,y,i=1;i<=Q;i++) {
    		opt=read();x=read(),y=read();
    		if(opt) {
    			if(st[x]>st[y]) std::swap(x,y);
    			int lca=LCA(x,y);++cnt;
    			if(lca==x) q[cnt].l=st[x],q[cnt].r=st[y];
    				else q[cnt].l=ed[x],q[cnt].r=st[y],q[cnt].o=lca;
    			q[cnt].rk=cnt;q[cnt].t=tot;
    		}
    		else pos[++tot]=x,val[tot]=y;
    	}
    	sz=pow(2*n,0.66666666);
    	for(re int i=1;i<=n*2;i++) id[i]=(i-1)/sz+1;
    	std::sort(q+1,q+cnt+1,cmp);
    	int l=0,r=0,now=0;
    	for(re int i=1;i<=cnt;i++) {
    		while(r<q[i].r) add(++r);
    		while(l>q[i].l) add(--l);
    		while(r>q[i].r) del(r--);
    		while(l<q[i].l) del(l++);
    		while(now<q[i].t) change(++now,i);
    		while(now>q[i].t) change(now--,i);
    		Ans[q[i].rk]=ans;
    		if(q[i].o) 
    			Ans[q[i].rk]+=1ll*(w[tmp[col[q[i].o]]+1])*a[col[q[i].o]];
    	}
    	for(re int i=1;i<=cnt;i++) printf("%lld
    ",Ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    在 Windows 上测试 Redis Cluster的集群填坑笔记
    vmware安装黑苹果教程
    微信支付v3发布到iis时的证书问题
    Linux下安装SQL Server 2016(连接篇SQL Server on linux)
    Linux下安装SQL Server 2016(连接篇SQL Server on linux)
    Linux下安装SQL Server 2016(安装篇SQL Server on linux)
    Linux下安装SQL Server 2016(准备篇SQL Server on linux)
    客服端与服务端APP支付宝支付接口联调的那些坑
    ASP.NET MVC]WebAPI应用支持HTTPS的经验总结
    .net平台下C#socket通信(中)
  • 原文地址:https://www.cnblogs.com/asuldb/p/10681680.html
Copyright © 2011-2022 走看看