两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
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); |