并不对劲的p2664树上游戏
题目大意
有一棵\(n\)(\(n\leq10^5\))个点的树,每个点\(i\)有颜色\(c_i\)(\(c_i\leq10^5\))
定义一条路径的得分为这条路径上的不同颜色个数
分别求每个点的以该点出发的所有路径的得分总和
题解
统计和路径有关的东西,让人想到点分治
找到当前区域的重心后,计算所有过重心的路径的影响
记每个当前区域里的点\(i\)以重心为根时,当前区域里的子树大小为\(siz_i\)
先分别算出每个颜色\(i\),对“从重心出发的所有路径的得分总和”的贡献\(W_i\)
发现如果一个点\(i\)的颜色\(c_i\)是从重心到它的路径上第一次出现的,那么它对于每条“以重心为起点,以它子树里的点为终点”的路径都会产生1的贡献,即\(W_{c_i}+=siz_i\)
然后遍历当前区域,对于每种颜色\(i\),记\(w_i\)表示当前遍历的重心的儿子的子树里,颜色\(i\)对\(W_i\)的贡献为\(w_i\)(也就是说,\(W_i-w_i\)表示颜色\(i\)对“从重心出发的所有不经过当前遍历的重心的儿子路径的得分总和”的贡献)
记\(x\)表示过重心的路径对当前遍历到的点的贡献,初始值为\(\Sigma (W_i-w_i)\)
如果当前点\(i\)的颜色不是在重心到它的路径上第一次出现的,那么\(x\)不变
如果当前点\(i\)的颜色是在重心到它的路径上第一次出现的,\(c_i\)本来只对终点在大小为\(W_{c_i}\)的区域中的路径有贡献,而现在对所有终点不和\(i\)在一个重心的儿子的子树里的路径都有贡献
\(x+=-(W_{c_i}-w_{c_i})+siz_{重心}-siz_{是当前点祖先的重心的儿子}\)
画个图说明一下:

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 100010
#define LL long long
#define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
using namespace std;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}
void write(LL x)
{
	if(x==0){putchar('0'),putchar('\n');return;}
	int f=0;char ch[20];
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
	return;
}
int n,c[maxn],fir[maxn],nxt[maxn<<1],v[maxn<<1],siz[maxn],cnt,wt,sumsiz,mnsz,vis[maxn],ext[maxn];
LL sum[maxn],sumall,num[maxn],numnow[maxn],sumnow;
void ade(int u1,int v1){v[cnt]=v1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
void getwt(int u,int fa)
{
	siz[u]=1;int nowmax=0;
	view(u,k)if(!vis[v[k]]&&v[k]!=fa)getwt(v[k],u),siz[u]+=siz[v[k]],nowmax=max(nowmax,siz[v[k]]);
	if(max(nowmax,sumsiz-siz[u])<mnsz)mnsz=max(nowmax,sumsiz-siz[u]),wt=u;return;
}
void getsz(int u,int fa)
{
	siz[u]=1;
	view(u,k)if(!vis[v[k]]&&v[k]!=fa)getsz(v[k],u),siz[u]+=siz[v[k]];return;
}
void getc(int u,int fa,int f)
{
	int yes=0;
	if(!ext[c[u]])ext[c[u]]=1,yes=1;
	view(u,k)if(!vis[v[k]]&&v[k]!=fa)getc(v[k],u,f);
	if(yes)ext[c[u]]=0,num[c[u]]+=f*siz[u],sumall+=f*siz[u];return;
}
void getnow(int u,int fa,int f)
{
	int yes=0;
	if(!ext[c[u]])ext[c[u]]=1,yes=1;
	view(u,k)if(!vis[v[k]]&&v[k]!=fa)getnow(v[k],u,f);
	if(yes)ext[c[u]]=0,numnow[c[u]]+=f*siz[u],sumnow+=f*siz[u];return;
}
void addsum(int u,int fa,LL ad,LL szanc)
{
	int yes=0;sum[u]+=ad;
	if(!ext[c[u]])yes=1,ext[c[u]]=1,sum[u]+=-(num[c[u]]-numnow[c[u]])+(LL)sumsiz-szanc;
	view(u,k)if(!vis[v[k]]&&v[k]!=fa)addsum(v[k],u,yes?ad-(num[c[u]]-numnow[c[u]])+(LL)sumsiz-szanc:ad,szanc);
	if(yes)ext[c[u]]=0;
}
void getans(int u,int nowsiz)
{
	sumsiz=nowsiz,mnsz=n+1,wt=sumall=0,getwt(u,0);int now=wt;
	getsz(now,0),getc(now,0,1);sum[now]+=sumall;ext[c[now]]=1;
	view(now,k)if(!vis[v[k]])numnow[c[now]]=siz[v[k]],sumnow=siz[v[k]],getnow(v[k],now,1),addsum(v[k],now,sumall-sumnow,siz[v[k]]),getnow(v[k],now,-1),numnow[c[now]]=0;
	ext[c[now]]=0;
	getc(now,0,-1); vis[now]=1;
	view(now,k)if(!vis[v[k]])getans(v[k],siz[v[k]]);return;
}
int main()
{
	n=read();
	memset(fir,-1,sizeof(fir));
	rep(i,1,n)c[i]=read();
	rep(i,1,n-1){int x=read(),y=read();ade(x,y),ade(y,x);}
	getans(1,n);
	rep(i,1,n)write(sum[i]);
	return 0;
}
一些感想
泡狐龙的bgm“妖艶なる舞 〜 タマミツネ”太好听了
并不对劲的p2664树上游戏的更多相关文章
- 洛谷 P2664 树上游戏 解题报告
		
P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...
 - P2664 树上游戏
		
P2664 树上游戏 https://www.luogu.org/problemnew/show/P2664 分析: 点分治. 首先关于答案的统计转化成计算每个颜色的贡献. 1.计算从根出发的路径的答 ...
 - Luogu P2664 树上游戏 dfs+树上统计
		
题目: P2664 树上游戏 分析: 本来是练习点分治的时候看到了这道题.无意中发现题解中有一种方法可以O(N)解决这道题,就去膜拜了一下. 这个方法是,假如对于某一种颜色,将所有这种颜色的点全部删去 ...
 - ●洛谷P2664 树上游戏
		
题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...
 - 洛谷P2664 树上游戏(点分治)
		
传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...
 - 洛谷P2664 树上游戏
		
https://www.luogu.org/problemnew/show/P2664 #include<cstdio> #include<algorithm> #includ ...
 - [LuoGu]P2664 树上游戏
		
Portal 这题真的好. 看到树上路径, 脑子里就要点分治 这一题对于每个点都要计算一遍, 如果暴算实在不好算, 这样我们就可以考虑算贡献. 直接计算每种颜色的贡献. 因为一条过重心的路径中, 可能 ...
 - 洛谷P2664 树上游戏(点分治)
		
题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...
 - 【刷题】洛谷 P2664 树上游戏
		
题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 \[sum_i=\sum_{j=1}^ns(i,j)\] 现在他想让你求出所有 ...
 
随机推荐
- Ural 1960 Palindromes and Super Abilities
			
Palindromes and Super Abilities Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged ...
 - Leetcode 319.灯泡开关
			
灯泡开关 初始时有 n 个灯泡关闭.第 1 轮,你打开所有的灯泡.第 2 轮,每两个灯泡你关闭一次.第 3 轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭).第 i 轮,每 i 个灯泡切换 ...
 - Codeforces947D. Picking Strings
			
$n \leq 100000,m \leq 100000$,给长度$n$的字符串$s$和$m$的字符串$t$,只含ABC.定义串$a$可以经过任意次如下操作变成其他串. 现在$q \leq 10000 ...
 - Free命令详解和释放linux Cache(转载)
			
因为LINUX的内核机制,一般情况下不需要特意去释放已经使用的cache.这些cache起来的内容可以增加文件以及的读写速度. 先说下free命令怎么看内存 [root@yuyii proc]# fr ...
 - mysql写入数据乱码问题的解决
			
mysql默认编码为latin. 我的mysql版本为5.6.安装路径下没有my.ini,但是有my-default.ini.其实mysql没有配置文件也是可以启动的,但是为了设置编码,需要将my-d ...
 - 如何使用shell收集linux系统状态,并把结果发给远端服务器
			
第一步:收集系统当天状态 load状态 内存状态 cpu状态 jvm相关信息:jstat jstack 网络信息 硬盘信息 第二步:发送到远端服务器 使用curl.wget.定义接口. https:/ ...
 - RabbitMQ Hello World
			
RabbitMQ Hello World rabbitmq operation: C:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.2\sbin ...
 - UI 07 _ 导航视图控制器 与 属性传值
			
首先, 先创建三个VC. 完毕点击按钮, 进入下一页, 并可以返回. 要先把导航视图控制器创建出来. 在AppDelegate.m 文件里代码例如以下: #import "AppDelega ...
 - Cocos2d-x 3.1.1 学习日志12--一Cocos2dx3.1.1移植到Android平台的方法(最实用最有效的!!)
			
须要用到工具(依照顺序): 1.JDK 2.NDK 3.ANT 4.Adt-bundle-windows 将JDK文件夹下的bin文件夹路径加入到系统环境变量中. 解压NDK 解压Adt-bundle ...
 - C++中防止STL中迭代器失效——map/set等关联容器——vector/list/deque等序列容器—如何防止迭代器失效—即erase()的使用
			
序列性容器::(vector和list和deque) erase迭代器不仅使所有指向被删元素的迭代器失效,而且使被 删元素之后的所有迭代器失效,所以不能使用erase(iter++)的方 式, ...