Warning: session_start(): open(/tmp/sess_1baff6dff3503f856ff69a5e290e9fba, O_RDWR) failed: No space left on device (28) in /data/wiki/inc/init.php on line 239

Warning: session_start(): Failed to read session data: files (path: ) in /data/wiki/inc/init.php on line 239

Warning: Cannot modify header information - headers already sent by (output started at /data/wiki/inc/init.php:239) in /data/wiki/inc/auth.php on line 430

Warning: Cannot modify header information - headers already sent by (output started at /data/wiki/inc/init.php:239) in /data/wiki/inc/actions.php on line 38

Warning: Cannot modify header information - headers already sent by (output started at /data/wiki/inc/init.php:239) in /data/wiki/lib/tpl/dokuwiki/main.php on line 12
2020-2021:teams:legal_string:jxm2001:静态点分治 [CVBB ACM Team]

用户工具

站点工具


2020-2021:teams:legal_string:jxm2001:静态点分治

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
2020-2021:teams:legal_string:jxm2001:静态点分治 [2020/06/05 22:39]
jxm2001
2020-2021:teams:legal_string:jxm2001:静态点分治 [2020/07/26 15:53] (当前版本)
jxm2001 ↷ 页面2020-2021:teams:legal_string:静态点分治被移动至2020-2021:teams:legal_string:jxm2001:静态点分治
行 46: 行 46:
 } }
 void solve(int u){ void solve(int u){
 + int cur_sz=tot_sz;​
  vis[u]=true;​query(u);​  vis[u]=true;​query(u);​
  for(int i=head[u];​i;​i=edge[i].next){  for(int i=head[u];​i;​i=edge[i].next){
行 51: 行 52:
  if(vis[v])  if(vis[v])
  continue;  continue;
- tot_sz=sz[v];​root_sz=inf;+ tot_sz=sz[v]>​sz[u]?​cur_sz-sz[u]:​sz[v];​root_sz=MAXN;
  find_root(v,​u);​  find_root(v,​u);​
  solve(root);​  solve(root);​
行 84: 行 85:
 <hidden 代码> <hidden 代码>
 <code cpp> <code cpp>
-#include <​cstdio>​ 
-#include <​cctype>​ 
-#include <​vector>​ 
-#define _for(i,a,b) for(int i=(a);​i<​(b);​++i) 
-using namespace std; 
-inline int read_int(){ 
- int t=0;bool sign=false;​char c=getchar();​ 
- while(!isdigit(c)){sign|=c=='​-';​c=getchar();​} 
- while(isdigit(c)){t=(t<<​1)+(t<<​3)+(c&​15);​c=getchar();​} 
- return sign?-t:t; 
-} 
 const int MAXN=1e4+5,​inf=1e7+5;​ const int MAXN=1e4+5,​inf=1e7+5;​
 struct Edge{ struct Edge{
行 139: 行 129:
 void query(int u){ void query(int u){
  sd.clear();​  sd.clear();​
 + mark[0]=true;​
  for(int i=head[u];​i;​i=edge[i].next){  for(int i=head[u];​i;​i=edge[i].next){
  d.clear();​  d.clear();​
行 162: 行 153:
 } }
 void solve(int u){ void solve(int u){
- vis[u]=mark[0]=true;​query(u);​+ int cur_sz=tot_sz;​ 
 + vis[u]=true;​query(u);​
  for(int i=head[u];​i;​i=edge[i].next){  for(int i=head[u];​i;​i=edge[i].next){
  int v=edge[i].to;​  int v=edge[i].to;​
  if(vis[v])  if(vis[v])
  continue;  continue;
- tot_sz=sz[v];​root_sz=inf;+ tot_sz=sz[v]>​sz[u]?​cur_sz-sz[u]:​sz[v];​root_sz=MAXN;
  find_root(v,​u);​  find_root(v,​u);​
  solve(root);​  solve(root);​
行 209: 行 201:
 <hidden 代码> <hidden 代码>
 <code cpp> <code cpp>
-#include <​cstdio>​ 
-#include <​cctype>​ 
-#include <​vector>​ 
-#define _for(i,a,b) for(int i=(a);​i<​(b);​++i) 
-using namespace std; 
-inline int read_int(){ 
- int t=0;bool sign=false;​char c=getchar();​ 
- while(!isdigit(c)){sign|=c=='​-';​c=getchar();​} 
- while(isdigit(c)){t=(t<<​1)+(t<<​3)+(c&​15);​c=getchar();​} 
- return sign?-t:t; 
-} 
 const int MAXN=2e5+5,​inf=1e6+5;​ const int MAXN=2e5+5,​inf=1e6+5;​
 struct Edge{ struct Edge{
行 285: 行 266:
 } }
 void solve(int u){ void solve(int u){
 + int cur_sz=tot_sz;​
  vis[u]=true;​query(u);​  vis[u]=true;​query(u);​
  for(int i=head[u];​i;​i=edge[i].next){  for(int i=head[u];​i;​i=edge[i].next){
行 290: 行 272:
  if(vis[v])  if(vis[v])
  continue;  continue;
- tot_sz=sz[v];​root_sz=MAXN;​+ tot_sz=sz[v]>​sz[u]?​cur_sz-sz[u]:​sz[v];​root_sz=MAXN;​
  find_root(v,​u);​  find_root(v,​u);​
  solve(root);​  solve(root);​
行 350: 行 332:
 定义 $s(i,j)$ 为 $i$ 到 $j$ 的颜色数量,$\text{sum}_i=\sum_{j=1}^n s(i,​j)$,要求输出所有 $\text{sum}_i$。 定义 $s(i,j)$ 为 $i$ 到 $j$ 的颜色数量,$\text{sum}_i=\sum_{j=1}^n s(i,​j)$,要求输出所有 $\text{sum}_i$。
  
-这题需要计算贡献,较复杂这里只给代码供参考,时间复杂度 $O(n\log n)$,另外本题存在 $O(n)$ 解法,有兴趣的可以自己尝试。+这题需要计算贡献,先考虑根结点,仅一端为根结点的径对根结点的答案有贡献。 
 + 
 +考虑 dfs 处理子树若一条路径上的某种颜色第一次现,立刻计算它的贡献,贡献为它所在的子树大小。 
 + 
 +经过这遍 dfs ,可以得到所有子树到根结点的贡献。 
 + 
 +虑所有经过根结点的路径(包含一端为根结点的路径)对所有子树结点答案的影响。 
 + 
 +对每棵子树上的结点而言,所有经过根结点的路径可以分为一条从其他子树到根结点的路径(也可以是空路径)和一条从根结点到该结点的路径。 
 + 
 +可以考虑多次利用之前计算出的所有子树到根结点的贡献。 
 + 
 +对每棵子树,先消去该子树对根结点的贡献,便可以得到所有其他子树到根结点的路径贡献。 
 + 
 +再重新对该子树进行遍历更新该子树上每个点的贡献值。 
 + 
 +最后把消去子树对根结点的贡献再改回去即可。 
 + 
 +时间复杂度 $O(n\log n)$ ,另外本题存在 $O(n)$ 解法,有兴趣的可以自己尝试。
  
 <hidden 代码> <hidden 代码>
 <code cpp> <code cpp>
-#include <​cstdio>​ 
-#include <​cctype>​ 
-#include <​vector>​ 
-#define _for(i,a,b) for(int i=(a);​i<​(b);​++i) 
-using namespace std; 
-typedef long long LL; 
-inline int read_int(){ 
- int t=0;bool sign=false;​char c=getchar();​ 
- while(!isdigit(c)){sign|=c=='​-';​c=getchar();​} 
- while(isdigit(c)){t=(t<<​1)+(t<<​3)+(c&​15);​c=getchar();​} 
- return sign?-t:t; 
-} 
-inline void write(LL x){ 
- register char c[21],​len=0;​ 
- if(!x)return putchar('​0'​),​void();​ 
- if(x<​0)x=-x,​putchar('​-'​);​ 
- while(x)c[++len]=x%10,​x/​=10;​ 
- while(len)putchar(c[len--]+48);​ 
-} 
-inline void space(LL x){write(x),​putchar('​ ');} 
-inline void enter(LL x){write(x),​putchar('​\n'​);​} 
 const int MAXN=1e5+5; const int MAXN=1e5+5;
 struct Edge{ struct Edge{
行 477: 行 456:
 } }
 void solve(int u){ void solve(int u){
 + int cur_sz=tot_sz;​
  vis[u]=true;​query(u);​  vis[u]=true;​query(u);​
  for(int i=head[u];​i;​i=edge[i].next){  for(int i=head[u];​i;​i=edge[i].next){
行 482: 行 462:
  if(vis[v])  if(vis[v])
  continue;  continue;
- tot_sz=sz[v];​root_sz=MAXN;​+ tot_sz=sz[v]>​sz[u]?​cur_sz-sz[u]:​sz[v];​root_sz=MAXN;​
  find_root(v,​u);​  find_root(v,​u);​
  solve(root);​  solve(root);​
2020-2021/teams/legal_string/jxm2001/静态点分治.1591367970.txt.gz · 最后更改: 2020/06/05 22:39 由 jxm2001