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;
}

noip模拟48的更多相关文章

  1. CH Round #48 - Streaming #3 (NOIP模拟赛Day1)

    A.数三角形 题目:http://www.contesthunter.org/contest/CH%20Round%20%2348%20-%20Streaming%20%233%20(NOIP模拟赛D ...

  2. NOIP模拟题汇总(加厚版)

    \(NOIP\)模拟题汇总(加厚版) T1 string 描述 有一个仅由 '0' 和 '1' 组成的字符串 \(A\),可以对其执行下列两个操作: 删除 \(A\)中的第一个字符: 若 \(A\)中 ...

  3. 【HHHOJ】NOIP模拟赛 玖 解题报告

    点此进入比赛 得分: \(100+20+100=220\)(还不错) 排名: \(Rank\ 16\) \(Rating\):\(+20\) \(T1\):[HHHOJ263]「NOIP模拟赛 玖」三 ...

  4. 【HHHOJ】NOIP模拟赛 捌 解题报告

    点此进入比赛 得分: \(30+30+70=130\)(弱爆了) 排名: \(Rank\ 22\) \(Rating\):\(-31\) \(T1\):[HHHOJ260]「NOIP模拟赛 捌」Dig ...

  5. NOIP模拟 1

    NOIP模拟1,到现在时间已经比较长了.. 那天是6.14,今天7.18了 //然鹅我看着最前边缺失的模拟1,还是终于忍不住把它补上,为了保持顺序2345重新发布了一遍.. #   用  户  名   ...

  6. NOIP模拟17.9.22

    NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥

  7. NOIP 模拟4 T2

    本题属于二和一问题 子问题相互对称 考虑对于问题一:知a求b 那么根据b数组定义式 显然能发现问题在于如何求dis(最短路) 有很多算法可供选择 dijsktra,floyed,bfs/dfs,spf ...

  8. 2021.9.17考试总结[NOIP模拟55]

    有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...

  9. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

随机推荐

  1. C# 为什么你应该更喜欢 is 关键字而不是 == 运算符

    前言 在C# 进行开发中,检查参数值是否为null大家都用什么?本文介绍除了传统的方式==运算符,还有一种可以商用is关键字. C# 7.0 中 is 关键字的使用 传统的方式是使用==运算符: if ...

  2. C++面向对象总结——虚指针与虚函数表

    最近在逛B站的时候发现有候捷老师的课程,如获至宝.因此,跟随他的讲解又复习了一遍关于C++的内容,收获也非常的大,对于某些模糊的概念及遗忘的内容又有了更深的认识. 以下内容是关于虚函数表.虚函数指针, ...

  3. 跟我一起写 Makefile(九)

    使用函数 ---- 在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能.make所支持的函数也不算很多,不过已经足够我们的操作了.函数调用后,函数的返回值可以当做 ...

  4. VIM的跨行查找和匹配数量

    跨行用\n表示,例如 用4\n56可以匹配到: 4 56 中,查询一段文本中pattern出现的次数,类似于UltraEdit中的"Count All"功能,用:%s/patter ...

  5. 计算机专业学了快一年, 只会一点C语言,你好意思说自己是IT专业的?

    目录 一.C/C++入门阶段 学习视频推荐:C++入门基础[B站 小甲鱼] 二.C/C++开发进阶 学习视频推荐:C++进阶[慕课网 免费课] 三.C++开发高级 视频教程:程序设计[中国大学MOOC ...

  6. 模拟退火 Simulated annealing

    模拟退火 Simulated annealing 看看有空把图片完善一下好了 模拟退火算法的一些背景 既然要说模拟退火算法,就应该说一下模拟退火算法的背景,模拟退火算法是局部搜索算法的一种扩展,该算法 ...

  7. 脚本小子学习--vulnhub靶机DC8

    @ 目录 前言 一.环境搭建 二.目标和思路 三.实际操作 1.信息收集 2.getshell 总结 前言 通过一些靶机实战练习,学习使用现有的工具来成为脚本小子. 一.环境搭建 靶机:Linux虚拟 ...

  8. Apache Druid 远程代码执行 CVE-2021-25646 漏洞复现

    Apache Druid 远程代码执行 CVE-2021-25646 漏洞复现 前言 Apache Druid 是用Java编写的面向列的开源分布式数据存储,旨在快速获取大量事件数据,并在数据之上提供 ...

  9. 【工作篇】了解升级 Spring 版本导致的跨域问题

    一.背景 最近需要统一升级 Spring 的版本,避免 common 包和各个项目间的 Spring 版本冲突问题.这次升级主要是从 Spring 4.1.9.RELEASE 升级到 Spring 4 ...

  10. SpringCloud升级之路2020.0.x版-18.Eureka的客户端核心设计和配置

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford Eureka 客户 ...