JZOJ6869. 【2020.11.17提高组模拟】pastel

14 篇文章 0 订阅
5 篇文章 0 订阅

Description

在这里插入图片描述

  • n ≤ 3 e 5 , q ≤ 5 e 5 n\le3e5,q\le5e5 n3e5,q5e5

Solution

  • 考虑维护每一个黑点,如果没有修改,子树查询可以把子树内的每一个黑点的 w ∗ c n t w*cnt wcnt求和,再考虑这个点的归属点权值 v v v,贡献 v ∗ ( s z x − ∑ c n t ) v*(sz_x-\sum cnt) v(szxcnt),单点查询可以直接询问归属点的权值,用一个线段树维护上面的值,以及4操作。
  • 如果有加入黑点的操作,简单维护一下上面的东西,把新黑点的权值变为它的归属点的权值。
  • 如果有加入白点的操作,还要把这个点的权值贡献到子树内,可以直接子树加,然后再做一次4操作容斥掉。
  • 查询一个点的归属点可以链剖+set,查询当前重链最浅的点,再二分。
  • O ( n   l o g   n ) O(n\ log\ n) O(n log n)
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#define maxn 300005
#define uint unsigned int
using namespace std;

int n,q,i,j,k,fa[maxn];
int em,e[maxn],nx[maxn],ls[maxn];
int tot,dfn[maxn],top[maxn],Idfn[maxn],sz[maxn],g[maxn],dep[maxn];

void read(int &x){
	x=0; char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
}

void insert(int x,int y){
	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
}

struct Treearray{
	uint s[maxn];
	void add(int x,uint d){for(;x<=n;x+=x&-x) s[x]+=d;}
	uint sum(int x,uint S=0){for(;x;x-=x&-x) S+=s[x];return S;}
	uint query(int l,int r){return sum(r)-sum(l-1);}
};

struct data{
	Treearray K,B;
	void add(int l,int r,uint d){
		K.add(l,d),K.add(r+1,-d);
		B.add(l,d*(-l+1)),B.add(r+1,-d*(-l+1));
		B.add(r+1,d*(r-l+1));
	}
	uint query(int l,int r){
		return K.sum(r)*r+B.sum(r)-K.sum(l-1)*(l-1)-B.sum(l-1);
	}
} ps;

void dfs1(int x,int p){
	sz[x]=1;
	for(int i=ls[x];i;i=nx[i]) {
		dfs1(e[i],x),sz[x]+=sz[e[i]];
		if (!g[x]||sz[e[i]]>sz[g[x]]) g[x]=e[i];
	}
}

void dfs2(int x,int p){
	if (p==0) top[x]=x;
	dfn[x]=++tot,Idfn[tot]=x,dep[x]=dep[p]+1;
	if (g[x]) top[g[x]]=top[x],dfs2(g[x],x);
	for(int i=ls[x];i;i=nx[i]) if (e[i]!=g[x])
		top[e[i]]=e[i],dfs2(e[i],x);
}

set<int> d[maxn];
set<int>::iterator it;
int gettop(int x){
	while (1){
		if (!d[top[x]].empty()){
			if (*d[top[x]].begin()<=dep[x])	{
				it=d[top[x]].upper_bound(dep[x]);
				it--;
				return Idfn[dfn[x]-(dep[x]-(*it))];
			}
		}
		x=fa[top[x]];
	}
}

int col[maxn];
uint ts[maxn*4],tc[maxn*4],tv[maxn*4],tag[maxn*4];
void upd(int x){
	ts[x]=ts[x<<1]+ts[x<<1^1];
	tc[x]=tc[x<<1]+tc[x<<1^1];
	tv[x]=tv[x<<1]+tv[x<<1^1];
}
void downtag(int x,int l,int r){
	if (!tag[x]) return;
	tv[x]+=tag[x];
	ts[x]+=tag[x]*tc[x];
	if (l<r) tag[x<<1]+=tag[x],tag[x<<1^1]+=tag[x];
	tag[x]=0;
}
void changev(int x,int l,int r,int L,int R,uint d){
	downtag(x,l,r);
	if (l>R||r<L) return;
	if (L<=l&&r<=R){
		tag[x]+=d,downtag(x,l,r);
		return;
	}
	int mid=(l+r)>>1;
	changev(x<<1,l,mid,L,R,d);
	changev(x<<1^1,mid+1,r,L,R,d);
	upd(x);
}
void changec(int x,int l,int r,int p,uint d){
	downtag(x,l,r);
	if (r<p||l>p) return;
	if (l==p&&l==r) {
		tc[x]+=d,ts[x]+=d*tv[x];
		return;
	}
	int mid=(l+r)>>1;
	changec(x<<1,l,mid,p,d);
	changec(x<<1^1,mid+1,r,p,d);
	upd(x);
}
uint getv(int x,int l,int r,int p){
	downtag(x,l,r);
	if (l==p&&l==r) return tv[x];
	int mid=(l+r)>>1;
	if (p<=mid) return getv(x<<1,l,mid,p);
	else return getv(x<<1^1,mid+1,r,p);
}
uint getc(int x,int l,int r,int L,int R){
	if (l>R||r<L) return 0;
	if (L<=l&&r<=R) return tc[x];
	int mid=(l+r)>>1;
	return getc(x<<1,l,mid,L,R)+getc(x<<1^1,mid+1,r,L,R);
}
uint gets(int x,int l,int r,int L,int R){
	downtag(x,l,r);
	if (l>R||r<L) return 0;
	if (L<=l&&r<=R) return ts[x];
	int mid=(l+r)>>1;
	return gets(x<<1,l,mid,L,R)+gets(x<<1^1,mid+1,r,L,R);
}
void coverv(int x,int l,int r,int p,uint v){
	downtag(x,l,r);
	if (r<p||l>p) return;
	if (l==p&&l==r) {tv[x]=v;ts[x]=v*tc[x];return;}
	int mid=(l+r)>>1;
	coverv(x<<1,l,mid,p,v),coverv(x<<1^1,mid+1,r,p,v);
	upd(x);
}

void reverse(int x){
	if (col[x]){
		col[x]=0;
		int cnt=sz[x]-getc(1,1,n,dfn[x]+1,dfn[x]+sz[x]-1);
		int y=gettop(fa[x]); d[top[x]].erase(dep[x]);
		uint vx=getv(1,1,n,dfn[x]);
		uint vy=getv(1,1,n,dfn[y]);
		changec(1,1,n,dfn[x],-cnt),coverv(1,1,n,dfn[x],0);
		changec(1,1,n,dfn[y],cnt);
		ps.add(dfn[x],dfn[x]+sz[x]-1,vx-vy);
		changev(1,1,n,dfn[x],dfn[x]+sz[x]-1,-(vx-vy));
	} else {
		col[x]=1;
		int cnt=sz[x]-getc(1,1,n,dfn[x]+1,dfn[x]+sz[x]-1);
		int y=gettop(x); d[top[x]].insert(dep[x]);
		uint vy=getv(1,1,n,dfn[y]);
		changec(1,1,n,dfn[x],cnt);
		changec(1,1,n,dfn[y],-cnt);
		coverv(1,1,n,dfn[x],vy);
	}
}

int main(){
	freopen("ceshi.in","r",stdin);
	freopen("ceshi.out","w",stdout);
//	freopen("pastel.in","r",stdin);
//	freopen("pastel.out","w",stdout);
	read(n),read(q);
	for(i=2;i<=n;i++) read(fa[i]),insert(fa[i],i);
	dfs1(1,0),dfs2(1,0);
	int cnt=0;
	col[1]=1,changec(1,1,n,dfn[1],sz[1]),d[1].insert(1);
	while (q--){
		int tp,x; read(tp),read(x);
		if (tp==1) 
			printf("%u\n",getv(1,1,n,dfn[gettop(x)])+ps.query(dfn[x],dfn[x]));
		if (tp==2)
			read(k),changev(1,1,n,dfn[x],dfn[x],k);
		if (tp==3){
			uint ans=getv(1,1,n,dfn[gettop(x)])*(sz[x]-getc(1,1,n,dfn[x]+1,dfn[x]+sz[x]-1));
			ans+=ps.query(dfn[x],dfn[x]+sz[x]-1);
			ans+=gets(1,1,n,dfn[x]+1,dfn[x]+sz[x]-1);
			printf("%u\n",ans);
		}
		if (tp==4)
			read(k),changev(1,1,n,dfn[x],dfn[x]+sz[x]-1,k);
		if (tp==5||tp==6)
			reverse(x);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值