ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

noip模拟48

2021-08-27 06:31:24  阅读:125  来源: 互联网

标签:return noip 48 int siz val maxn ans 模拟


A. Lighthouse

很明显的容斥题,组合式与上上场 \(t2\) 一模一样
注意判环时长度为 \(n\) 的环是合法的


B. Miner

题意实际上是要求偶拉路
对于一个有多个奇数点的联通块,直接 \(dfs\) 是不对的,可能搜索是来的不是一条路径
可以把个数大于 \(2\) 的联通块先强制奇数点两两连边,再跑两个奇数点的偶拉路
直接跑会 \(t\),可以加入类似当前弧优化,注意每次 \(dfs\) 回溯时也要更新边为当前弧

void dfs(int u){
	for(int i=hd[u];i;){
		hd[u]=edge[i].nxt;
		if(!vis[i>>1]){
			int v=edge[i].to;
			deg[u]--;
			deg[v]--;
			vis[i>>1]=true;
			dfs(v);
			sta1[++tp1]=make_pair(edge[i].val,v);
			i=hd[u];
		}
		else i=edge[i].nxt;
	}
	return ;
}

C. Lyk Love painting

这 \(m\) 幅画居然不能重叠……

首先肯定二分,然后 \(dp\) 验证
设 \(f[i][j]\) 表示第一行选到第 \(i\) 列总共选了 \(j\) 幅画第二行最远选到第几幅画
转移需要双指针预处理第一行,第二行,以及两行从每一列出发最远能到达的距离


D. Revive

先把平方拆开,分为两部分:

  • 对于每条边,其平方计算了经过这条边的路径数次,为 \(siz_u(n-siz_u)\)
  • 对于每两条边,其乘机的二倍计算了同时经过这两条边的路径次数
    可以分三类讨论:
  • \(v\) 在 \(u\) 子树内,为 \(2(n-siz[u]) * val[u] * siz[v] * val[v]\)
  • \(v\) 在 \(u\) 到根节点路径上,为 \(2siz[u] * val[u] * (n-siz[v]) * val[v]\)
  • \(v\) 和 \(u\) 的 \(lca\) 不是两点中的任意一个,为 \(2siz[u] * val[u] * siz[v] * val[v]\)

发现和 \(v\) 有关的式子都是 \(siz[v] * val[v]\),那么用线段树维护这个值即可
由于需要维护到根节点路径的值,可以另开一棵记录每个点到根节点的前缀和,这样转化成每次区间修改单点查询,避免了多次跳链的 \(log\)
子树内权值和可以用树状数组维护以卡常

代码实现
#include<bits/stdc++.h>
using namespace std;
#define in long long
#define int long long
const int maxn=1e5+5;
const int maxm=1e5+5;
const int mod=1e9+7;
const int stan=1e15;
in n,m,fa[maxn],x,siz[maxn],re[maxn],dfn[maxn],hd[maxn],cnt,num;
int ans,w,val[maxn],sum[maxn],sum1[maxn],sumtot,c[maxn];
in read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=x*10+ch-48;
		ch=getchar();
	}
	return x*f;
}
struct Edge{
	in nxt,to;
}edge[maxm];
void add(in u,in v){
	edge[++cnt].nxt=hd[u];
	edge[cnt].to=v;
	hd[u]=cnt;
	return ;
}
void change1(int x,int w){
	for(;x<=n;x+=x&-x)c[x]=(c[x]+w)%mod;
	return ;
}
int ask3(int x){
	int ans=0;
	for(;x;x-=x&-x)ans=(ans+c[x])%mod;
	return ans;
}
void modadd(int &x,int y){
	x=(x+y)%mod;
	if(x<0)x=(x+mod)%mod;
}
void dfs(in u){
	siz[u]=1;
	for(in i=hd[u];i;i=edge[i].nxt){
		in v=edge[i].to;
		dfs(v);
		siz[u]+=siz[v];
	}
	return ;
}
void dfs1(in u){
	sum[u]=(sum[fa[u]]+siz[u]*val[u]%mod)%mod;
	sum1[u]=(sum1[fa[u]]+val[u])%mod;
//	cout<<"ppp "<<sum1[u]<<endl;
	dfn[u]=++num;
	re[num]=u;
	for(in i=hd[u];i;i=edge[i].nxt){
		in v=edge[i].to;
		dfs1(v);
	}
	return ;
}
struct Seg{
	in l,r;
	int sum,lazy,sum1,lazy1,sum2,lazy2;
}t[maxn*4];
void update(in p){
	t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
	t[p].sum1=t[p<<1].sum1+t[p<<1|1].sum1;
//	if(t[p].sum>stan)t[p].sum%=mod;
//	if(t[p].sum1>stan)t[p].sum1%=mod;
//	t[p].sum2=t[p<<1].sum2+t[p<<1|1].sum2;
	return ;
}
void build(in p,in l,in r){
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		t[p].sum=sum[re[l]];
		t[p].sum1=sum1[re[l]];
//		t[p].sum2=siz[re[l]]*val[re[l]]%mod;
		return ;
	}
	in mid=l+r>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	update(p);
	return ;
}
void tospread(in p,int w1,int w2){
	t[p].lazy=t[p].lazy+w1;
	t[p].lazy1=t[p].lazy1+w2;
	
	t[p].sum=t[p].sum+w1;
	t[p].sum1=t[p].sum1+w2;
	
	return ;
}
//void tospread1(in p,int w){
//	t[p].lazy2=t[p].lazy2+w;
//	t[p].sum2=t[p].sum2+w;
//	return ;
//}
void spread(in p){
	tospread(p<<1,t[p].lazy,t[p].lazy1);
	tospread(p<<1|1,t[p].lazy,t[p].lazy1);
	t[p].lazy=t[p].lazy1=0;
	return ;
}
//void spread1(in p){
//	tospread1(p<<1,t[p].lazy2);
//	tospread1(p<<1|1,t[p].lazy2);
//	t[p].lazy2=0;
//	return ;
//}
void change(in p,in l,in r,int w1,int w2){
	if(l>r)return ;
	if(t[p].l>=l&&t[p].r<=r){
		tospread(p,w1,w2);
		return ;
	}
	if(t[p].lazy||t[p].lazy1)spread(p);
//	if(t[p].lazy2)spread1(p);
	in mid=t[p].l+t[p].r>>1;
	if(l<=mid)change(p<<1,l,r,w1,w2);
	if(r>mid)change(p<<1|1,l,r,w1,w2);
	update(p);
	return ;
}
//void change1(in p,in l,in r,int w){
//	if(l>r)return ;
//	if(t[p].l>=l&&t[p].r<=r){
//		tospread1(p,w);
//		return ;
//	}
//	if(t[p].lazy||t[p].lazy1)spread(p);
//	if(t[p].lazy2)spread1(p);
//	in mid=t[p].l+t[p].r>>1;
//	if(l<=mid)change1(p<<1,l,r,w);
//	if(r>mid)change1(p<<1|1,l,r,w);
//	update(p);
//	return ;
//}
int ask(in p,in l,in r){
//	cout<<t[p].l<<" "<<t[p].r<<"   "<<l<<" "<<r<<endl;
	if(l>r)return 0;
	if(t[p].l>=l&&t[p].r<=r)return t[p].sum;
	int mid=t[p].l+t[p].r>>1,ans=0;
	if(t[p].lazy||t[p].lazy1)spread(p);
//	if(t[p].lazy2)spread1(p);
	if(l<=mid)ans=ask(p<<1,l,r);
	if(r>mid)ans=ans+ask(p<<1|1,l,r);
	if(ans>stan)ans%=mod;
	return ans;
}
int ask1(in p,in l,in r){
	if(l>r)return 0;
	if(t[p].l>=l&&t[p].r<=r)return t[p].sum1;
	in mid=t[p].l+t[p].r>>1,ans=0;
	if(t[p].lazy||t[p].lazy1)spread(p);
//	if(t[p].lazy2)spread1(p);
	if(l<=mid)ans=ask1(p<<1,l,r);
	if(r>mid)ans=ans+ask1(p<<1|1,l,r);
	if(ans>stan)ans%=mod;
	return ans;
}
int ask2(in p,in l,in r){
	if(l>r)return 0;
	if(t[p].l>=l&&t[p].r<=r)return t[p].sum2;
	in mid=t[p].l+t[p].r>>1,ans=0;
	if(t[p].lazy||t[p].lazy1)spread(p);
//	if(t[p].lazy2)spread1(p);
	if(l<=mid)ans=ask2(p<<1,l,r);
	if(r>mid)ans=ans+ask2(p<<1|1,l,r);
	if(ans>stan)ans%=mod;
	return ans;
}
int solve(in u,int w,in op){
	int res=0;
	int sumz=0;
	if(siz[u]>1)sumz=ask3(dfn[u]+siz[u]-1)-ask3(dfn[u]);
//	int sumz=ask2(1,dfn[u]+1,dfn[u]+siz[u]-1);
//	cout<<"hhh "<<u<<" "<<sumz<<endl;
//	cout<<ask(1,dfn[u]+1,dfn[u]+siz[u]-1)<<" "<<ask(1,dfn[u],dfn[u])<<endl;
	//cout<<"hhh"<<endl;
	int suml=ask(1,dfn[fa[u]],dfn[fa[u]])%mod;
//	cout<<" "<<ask1(1,dfn[fa[u]],dfn[fa[u]])<<endl;
	modadd(res,ask1(1,dfn[fa[u]],dfn[fa[u]])%mod*n%mod-suml);
//	cout<<res<<endl;
//	cout<<sumtot<<" "<<suml<<" "<<sumz<<endl;
	modadd(res,sumtot-suml-siz[u]*val[u]%mod-sumz);
//	cout<<res<<endl;
	res=2*res*siz[u]%mod*w%mod;
//	cout<<res<<endl;
	modadd(res,2*w*(n-siz[u])%mod*sumz%mod);
//	cout<<"hhh "<<res<<endl;
//	cout<<res<<endl;
	if(op){
		change(1,dfn[u],dfn[u]+siz[u]-1,w*siz[u]%mod,w);
		change1(dfn[u],w*siz[u]%mod);
//		change1(1,dfn[u],dfn[u],w*siz[u]);
		modadd(sumtot,w*siz[u]%mod);
	}
	return res;
}
int po(int a,int b=mod-2){
	int ans=1;
	while(b){
		if(b&1)ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}
signed main(){
//	freopen("revive3.in","r",stdin);
//	freopen("shuju.in","r",stdin);
//	freopen("my.out","w",stdout);
	n=read();
	n=read(),m=read();
	for(int i=2;i<=n;i++){
		fa[i]=read();
		val[i]=read();
		add(fa[i],i);
	}
	dfs(1);
	dfs1(1);
	build(1,1,n);
	for(int i=1;i<=n;i++)change1(dfn[i],siz[i]*val[i]%mod);
	for(int i=1;i<=n;i++)modadd(sumtot,val[i]*siz[i]%mod);
	for(int i=2;i<=n;i++){
//		cout<<"id: "<<i<<endl;
//		cout<<solve(i,val[i],0)<<" ";
		ans=(ans+solve(i,val[i],0))%mod;
	}
	ans=ans*po(2)%mod;
//	cout<<ans<<endl;
	for(int i=2;i<=n;i++){
		ans=(ans+val[i]*val[i]%mod*siz[i]%mod*(n-siz[i])%mod)%mod;
	}
	cout<<ans<<endl;
	for(int i=1;i<=m;i++){
		x=read();
		w=read();
		ans=(ans-val[x]*val[x]%mod*siz[x]%mod*(n-siz[x])%mod)%mod;
		ans=(ans+mod)%mod;
		ans=(ans+solve(x,w,1))%mod;
		val[x]+=w;
		val[x]%=mod;
		ans=(ans+val[x]*val[x]%mod*siz[x]%mod*(n-siz[x])%mod)%mod;
		printf("%lld\n",ans);
	}
	return 0;
}

标签:return,noip,48,int,siz,val,maxn,ans,模拟
来源: https://www.cnblogs.com/yang-cx/p/15192288.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有