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 代码实现关机(直接黑屏)
    Windows SEH学习 x86
    Smali 语法文档
    SIOCADDRT: No such process
    Windbg 常用命令整理
    ida GDB 远程调试
    IDA 使用技巧
    Windows X64 Patch Guard
    C 和C++ 名称修饰规则
    【转载】 硬盘主引导记录(MBR)及其结构详解
  • 原文地址:https://www.cnblogs.com/asuldb/p/10681680.html
Copyright © 2011-2022 走看看