6362. 【NOIP2019模拟2019.9.18】数星星
题目描述



题解
一种好想/好写/跑得比**记者还快的做法:
对所有询问排序,按照R递增的顺序来处理
维护每个点最后一次被覆盖的时间,显然当前右端点为R时的答案为所有时间≥L的点的权值之和
LCT随便覆盖一发,保证一段重链上的点的颜色相同(这样可以直接修改),用树状数组维护权值和
由于要保证颜色相同,所以不能随便moveroot
覆盖时先把x和y的lca和原树上的父亲断掉,把x-->lca这一段覆盖,然后再覆盖y-->lca向y方向的儿子
反正随便写应该就能过(
另一种做法
也就是题解的难想/难写/跑得没**记者快的做法
原以为跑得很快就去写了一发
把每个L<R的询问下放到线段树上的一个l≤L≤mid且mid+1≤R≤r的区间[l,r]上(显然这样的区间是唯一的)
由于询问必定经过mid,所以每个询问可以表示成左边的贡献+右边的贡献
为了不算重,考虑维护把每个点的贡献放到当前区间内最早覆盖该点的路径上,算答案就直接求和
对于每个有询问的区间,把路径l~r的有关点建虚树(分点和段),依次把mid+1~r的每条边在虚树上覆盖,每个点/段记录下最早被覆盖的时间,用并查集优化,同时求出加入每条边之后新增的贡献,树状数组维护
接着按L从大到小处理每个询问,计算每加入一条路径时计算覆盖的贡献
因为L递减,所以每条路径加入后就不会删除,同时为了防止算重,要把这条路径上的贡献在树状数组上的原位置减去
然而这样似乎跑不过(
优化:
①RMQ求LCA(欧拉序,xy的lca=x~y路径上深度最浅的点的父亲)
②对于每个区间,R的扫描范围=mid+1~max(区间中询问的R)
code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define inc(x,y) (bg[x]<=bg[y] && ed[y]<=ed[x])
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define low(x) (x&-(x))
using namespace std;
struct type{
int x,y,id;
} q[100001];
int p[200001];
int P[18];
long long tr[100001];
int a[200001][2];
int b[200002];
int c[100001]; //final xushu
int ls[100001];
int A[100001][4];
int Ls[400001];
int w[100001];
int cl[100001];
int cr[100001];
int Lca[100001];
int bg[100001];
int ed[100001];
int Bg[100001];
int Ed[100001];
int fa[100001];
int D[100001];
int ql[100001];
int qr[100001];
int Fa[100001];
int Fa2[100001]; //beiyong
int d[100001];
long long ans[100001];
long long Sum[100001];
long long sum[100001]; //duan
long long num[100001]; //dian
long long Num[100001]; //duan
bool bz[100001]; //dian
bool Bz[100001]; //duan
int rmq[200001][18];
int B[200001]; //euler
int n,m,Q,i,j,k,l,len,Len,lenb,lenc,lenq,LEN,N,mr;
bool cmp(int a,int b)
{
return bg[a]<bg[b];
}
bool Cmp(type a,type b)
{
return a.x>b.x;
}
void New(int x,int y)
{
++len;
a[len][0]=y;
a[len][1]=ls[x];
ls[x]=len;
}
void NEW(int t,int x,int y,int id)
{
++Len;
A[Len][0]=x;
A[Len][1]=y;
A[Len][2]=id;
A[Len][3]=Ls[t];
Ls[t]=Len;
}
void swap(int &x,int &y)
{
int z=x;
x=y;
y=z;
}
void dfs(int Fa,int t)
{
int i;
B[++N]=t;
Bg[t]=N;
bg[t]=++j;
fa[t]=Fa;
D[t]=D[Fa]+1;
Sum[t]=Sum[Fa]+w[t];
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
dfs(t,a[i][0]);
B[++N]=t;
Ed[t]=N;
ed[t]=j;
}
int lca(int x,int y)
{
if (inc(x,y)) return x;
if (inc(y,x)) return y;
if (Bg[x]>Bg[y]) swap(x,y);
x=Bg[x],y=Ed[y];
int Len=y-x+1;
if (D[rmq[x][p[Len]]]<D[rmq[y-P[p[Len]]+1][p[Len]]])
return fa[rmq[x][p[Len]]];
else
return fa[rmq[y-P[p[Len]]+1][p[Len]]];
}
void change(int t,int l,int r,int x,int y,int id)
{
int mid=(l+r)/2;
if (x<=mid && mid+1<=y)
{
NEW(t,x,y,id);
return;
}
if (y<=mid)
change(t*2,l,mid,x,y,id);
else
change(t*2+1,mid+1,r,x,y,id);
}
void Change(int t,long long s)
{
while (t<=LEN)
{
tr[t]+=s;
t+=low(t);
}
}
void Clear(int t)
{
while (t<=LEN)
{
tr[t]=0;
t+=low(t);
}
}
long long Find(int t)
{
long long ans=0;
while (t)
{
ans+=tr[t];
t-=low(t);
}
return ans;
}
void build()
{
int i,j,k,l=0;
sort(b+1,b+lenb+1,cmp);
l=1;
d[1]=1;
fo(i,1,lenb)
if (b[i]!=d[l])
{
k=lca(b[i],d[l]);
while (!inc(d[l],k))
{
Fa2[d[l]]=d[l-1];
c[++lenc]=d[l];
--l;
}
if (d[l]!=k)
{
Fa2[d[l+1]]=k;
d[++l]=k;
}
d[++l]=b[i];
}
while (l)
{
Fa2[d[l]]=d[l-1];
c[++lenc]=d[l];
--l;
}
fo(i,1,lenc)
sum[c[i]]=Sum[c[i]]-Sum[Fa2[c[i]]]-w[c[i]];
}
void solve(int t,int L,int R)
{
int I,i,j,k,l,mid=(L+R)/2;
long long Ans=0,SUM;
LEN=R-L+1;
lenb=0;
lenc=0;
fo(i,L,R)
b[++lenb]=cl[i],b[++lenb]=cr[i];
build();
// right
fo(i,1,lenc)
num[c[i]]=0,Num[c[i]]=0,Fa[c[i]]=Fa2[c[i]];
fo(i,mid+1,mr)
{
SUM=0;
l=0;
j=cl[i];
while (!inc(j,Lca[i]))
{
d[++l]=j;
if (!num[j]) {num[j]=i;SUM+=w[j];}
if (!Num[j]) {Num[j]=i;SUM+=sum[j];}
j=Fa[j];
}
j=cr[i];
while (!inc(j,Lca[i]))
{
d[++l]=j;
if (!num[j]) {num[j]=i;SUM+=w[j];}
if (!Num[j]) {Num[j]=i;SUM+=sum[j];}
j=Fa[j];
}
if (!num[Lca[i]]) {num[Lca[i]]=i;SUM+=w[Lca[i]];}
fo(k,1,l)
Fa[d[k]]=Lca[i];
Change(i-L+1,SUM);
}
// left
fo(i,1,lenc)
Fa[c[i]]=Fa2[c[i]],bz[c[i]]=0,Bz[c[i]]=0;
q[0].x=mid+1;
fo(I,1,lenq)
{
fd(i,q[I-1].x-1,q[I].x)
{
SUM=0;
l=0;
j=cl[i];
while (!inc(j,Lca[i]))
{
d[++l]=j;
if (!bz[j]) {bz[j]=1;SUM+=w[j];}
if (!Bz[j]) {Bz[j]=1;SUM+=sum[j];}
if (num[j]) {Change(num[j]-L+1,-w[j]),num[j]=0;}
if (Num[j]) {Change(Num[j]-L+1,-sum[j]),Num[j]=0;}
j=Fa[j];
}
j=cr[i];
while (!inc(j,Lca[i]))
{
d[++l]=j;
if (!bz[j]) {bz[j]=1;SUM+=w[j];}
if (!Bz[j]) {Bz[j]=1;SUM+=sum[j];}
if (num[j]) {Change(num[j]-L+1,-w[j]),num[j]=0;}
if (Num[j]) {Change(Num[j]-L+1,-sum[j]),Num[j]=0;}
j=Fa[j];
}
if (!bz[Lca[i]]) {bz[Lca[i]]=1;SUM+=w[Lca[i]];}
if (num[Lca[i]]) {Change(num[Lca[i]]-L+1,-w[Lca[i]]),num[Lca[i]]=0;}
fo(k,1,l)
Fa[d[k]]=Lca[i];
Ans+=SUM;
}
ans[q[I].id]=Ans+Find(q[I].y-L+1);
}
// clear
memset(tr,0,(LEN+1)*8);
}
void work(int t,int l,int r)
{
int mid=(l+r)/2,i;
if (l==r) return;
if (Ls[t])
{
mr=l;
lenq=0;
for (i=Ls[t]; i; i=A[i][3])
{
++lenq;
q[lenq].x=A[i][0];
q[lenq].y=A[i][1];
q[lenq].id=A[i][2];
mr=max(mr,A[i][1]);
}
sort(q+1,q+lenq+1,Cmp);
solve(t,l,r);
}
work(t*2,l,mid);
work(t*2+1,mid+1,r);
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("b.out","w",stdout);
freopen("star.in","r",stdin);
freopen("star.out","w",stdout);
scanf("%d%d%d",&n,&m,&Q);
fo(i,1,n)
scanf("%d",&w[i]);
fo(i,2,n)
{
scanf("%d%d",&j,&k);
New(j,k);
New(k,j);
}
j=0;
dfs(0,1);
fo(i,1,N)
{
rmq[i][0]=B[i];
p[i]=floor(log(i)/log(2));
}
P[0]=1;
fo(i,1,17)
P[i]=P[i-1]<<1;
k=1;l=2;
fo(i,1,17)
{
fo(j,1,N-l+1)
if (D[rmq[j][i-1]]<D[rmq[j+k][i-1]])
rmq[j][i]=rmq[j][i-1];
else
rmq[j][i]=rmq[j+k][i-1];
k<<=1;l<<=1;
}
fo(i,1,m)
{
scanf("%d%d",&cl[i],&cr[i]);
Lca[i]=lca(cl[i],cr[i]);
}
fo(i,1,Q)
{
scanf("%d%d",&ql[i],&qr[i]);
if (ql[i]<qr[i])
change(1,1,m,ql[i],qr[i],i);
else
ans[i]=Sum[cl[ql[i]]]+Sum[cr[ql[i]]]-Sum[Lca[ql[i]]]-Sum[fa[Lca[ql[i]]]];
}
work(1,1,m);
fo(i,1,Q)
printf("%lld\n",ans[i]);
fclose(stdin);
fclose(stdout);
return 0;
}
6362. 【NOIP2019模拟2019.9.18】数星星的更多相关文章
- 6361. 【NOIP2019模拟2019.9.18】鲳数
题目 题目大意 给你一个区间\([l,r]\),求这个区间内每个整数的十进制上从高位到低位的逆序对个数之和. 思考历程 一开始就知道这是个数位DP-- 结果一直都没有调出来,心态崩了-- 正解 先讲讲 ...
- jzoj6009. 【THUWC2019模拟2019.1.18】Counting (dp)
Description 羽月最近发现,她发动能力的过程是这样的: 构建一个 V 个点的有向图 G,初始为没有任何边,接下来羽月在脑中构建出一个长度为 E 的边的序列,序列中元素两两不同,然后羽月将这些 ...
- 6392. 【NOIP2019模拟2019.10.26】僵尸
题目描述 题解 吼题但题解怎么这么迷 考虑一种和题解不同的做法(理解) 先把僵尸离散化,h相同的钦(ying)点一个大小 (可以发现这样每种情况只会被算正好一次) 计算完全被占领的方案,然后1-方案/ ...
- 6389. 【NOIP2019模拟2019.10.26】小w学图论
题目描述 题解 之前做过一次 假设图建好了,设g[i]表示i->j(i<j)的个数 那么ans=∏(n-g[i]),因为连出去的必定会构成一个完全图,颜色互不相同 从n~1染色,点i的方案 ...
- 6377. 【NOIP2019模拟2019.10.05】幽曲[埋骨于弘川]
题目描述 题解 随便bb 详细题解见 https://www.cnblogs.com/coldchair/p/11624979.html https://blog.csdn.net/alan_cty/ ...
- 【NOIP2019模拟2019.10.07】果实摘取 (约瑟夫环、Mobius反演、类欧、Stern-Brocot Tree)
Description: 小 D 的家门口有一片果树林,果树上果实成熟了,小 D 想要摘下它们. 为了便于描述问题,我们假设小 D 的家在二维平面上的 (0, 0) 点,所有坐标范围的绝对值不超过 N ...
- 6371. 【NOIP2019模拟2019.9.28】基础图论练习题
题目 题目大意 维护一个无向图的割边条数,支持加边和删边. 正解 (PS:这是我很久之前在OJ上打出来的题解,现在直接copy过来) 题解只有一句话,估计没多少人可以看得懂.感觉出题人偷懒不想写题解- ...
- 6374. 【NOIP2019模拟2019.10.04】结界[生与死的境界]
题目 题目大意 给你一个数列,每次可以选择任意两个相邻的数\(x\)和\(y\),将其删去,并在原来位置插入\(x+2y\). 每次询问一个区间,对这个区间进行上述操作.求最后剩下的数最大是多少. 答 ...
- NOIP2019模拟2019.9.20】膜拜大会(外向树容斥,分类讨论)
传送门. 题解: 我果然是不擅长分类讨论,心态被搞崩了. 注意到\(m<=n-2\),意味着除了1以外的位置不可能被加到a[1]两遍. 先考虑个大概: 考虑若存在\(x,x-1,-,2\)(有序 ...
随机推荐
- sql语句实现行转列的3种方法实例
sql语句实现行转列的3种方法实例 一般在做数据统计的时候会用到行转列,假如要统计学生的成绩,数据库里查询出来的会是这样的,但这并不能达到想要的效果,所以要在查询的时候做一下处理,下面话不多说了,来一 ...
- laravel 5.6 使用RabbitMQ作为消息中间件
1.Composer安装laravel-queue-rabbitmqcomposer require vladimir-yuldashev/laravel-queue-rabbitmq2.在confi ...
- LeetCode算法题-Flipping an Image(Java实现)
这是悦乐书的第324次更新,第347篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第194题(顺位题号是832).给定二进制矩阵A,我们想要水平翻转图像,然后反转它,并返 ...
- Java程序的运行过程,以及Java为什么能够跨平台
Java程序运行机制 Java的运行主要分两步:先编译再解释执行 (1)先通过“编译器”将Java源程序(.java)编译成Java字节码文件(.class) (2)通过不同的虚拟机(JVM)将字节 ...
- mysql驱动表与被驱动表及join优化
驱动表与被驱动表 先了解在join连接时哪个表是驱动表,哪个表是被驱动表:1.当使用left join时,左表是驱动表,右表是被驱动表2.当使用right join时,右表时驱动表,左表是驱动表3.当 ...
- 【监控笔记】【1.3】监控事件系列——SQL Trace(黑盒跟踪 BlackBox Trace)
[1]它跟踪了哪些事件? (1.1)存储过程执行(SP:Strating) (1.2)T-SQL执行(SQL:BatchString) (1.3)错误和警告(Exception,Attention) ...
- 使用extract-text-webpack-plugin插件后报错
如果你使用的webpack是4+版本,那么尝试运行npm install extract-text-webpack-plugin@next ,即可解决问题 然而最好的解决办法是在webpack4+的版 ...
- JS案例经验二
一 关键词:鼠标事件的触发 可以在函数中指定让鼠标事件自动触发,而不是必须要鼠标滑过才触发,例如: main.onmouseover(); // 可以把该语句看做是鼠标滑过的模拟动作 main是DOM ...
- Selenium1.0与2.0介绍
Selenium的实现原理 首先,你要明确刚才建立的测试用例是基于Selenium 2.0,也就是Selenium + WebDriver的方案.其次,你需要知道,对Selenium而言,V1.0和V ...
- electron实现qq快捷登录!
之前本来想不写这个功能的,结果客户死活要qq登录! 实在没办法就写了,顺便写个文章!在写之前有两个问题:1: 打开qq授权页面点击页面中的链接会又打开一个页面! .....2: 授权之后是否成功很难去 ...