[CSU - 1811 (湖南省赛16)] Tree Intersection (dfs序维护子树+离线询问+树状数组)

本文主要是介绍[CSU - 1811 (湖南省赛16)] Tree Intersection (dfs序维护子树+离线询问+树状数组),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

CSU - 1811 (湖南省赛16)

给定一棵树,每个节点都有一个颜色
问割掉任意一条边,生成的两个子树中颜色集合的交集大小


这个是 dfs序处理子树 + 离线询问 + bit维护 的解法
首先问题转化为求解一个子树中有多少种颜色以及独有颜色的数量
用总的颜色数量减去独有颜色数量即为这棵子树的答案
先做一遍 dfs,再按 dfs序重新组建颜色序列
这样对子树的询问,就变成了对序列上区间的询问
某个区间内有多少种颜色和独有颜色数量

然后离线所有询问,按区间右端点排序,然后从 1到 N地扫描这个区间
首先区间内颜色数量已经是很套路的做法了
只要预处理出第 i 个颜色上一次出现的位置 pre[i]
然后扫到 i 的时候,在 [pre[i]+1,i] 上都加 1 ,这样保证不会重复统计
其次区间内独有颜色计数,需要预处理出两个量
某个颜色第一次出现的位置 fir[i],以及最后出现的位置 las[i]
当扫到的颜色处于其最后出现的位置,那么区间左端点在 fir[i] 及之前时
这个颜色都会成为独有的颜色
所以只要在 [1,fir[i]1] 上都减 1 即可
这个区间操作,单点查询用树状数组维护即可
总的时间复杂度是 (nlogn),空间复杂度 (n)

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <string>
#include <complex>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define SQR(a) ((a)*(a))
#define PCUT puts("\n----------")const int maxn=1e5+10;
struct Graph
{int ndn, edn, last[maxn];int u[2*maxn], v[2*maxn], nxt[2*maxn];void init(int _n){ndn=_n; edn=0; MST(last,-1);}void adde(int _u, int _v){u[edn]=_u; v[edn]=_v;nxt[edn]=last[_u];last[_u]=edn++;}
};struct Query
{int l,r,id;bool operator < (const Query &rhs) const {return r < rhs.r;}
};struct BIT
{int bit[maxn], siz;void init(int _n){siz=_n; CLR(bit);}void add(int p, int x){for(; p<=siz; p+=p&-p) bit[p]+=x;}int sum(int p){int res=0; for(; p>0; p-=p&-p) res+=bit[p]; return res;}
};int N;
int col[maxn], fir[maxn], las[maxn], pre[maxn], ans[maxn], id[maxn];
int dfst, dfsn[maxn], que[maxn];
vector<Query> Q;
BIT bit;
Graph G;void dfs(int,int);int main()
{#ifdef LOCALfreopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);#endifwhile(~scanf("%d", &N)){MST(fir,-1); MST(las,-1); CLR(pre);G.init(N);for(int i=1; i<=N; i++) scanf("%d", &col[i]);for(int i=0,u,v; i<N-1; i++){scanf("%d%d", &u, &v);G.adde(u,v); G.adde(v,u);}Q.clear();dfst=0; CLR(dfsn);dfs(1,0);for(int i=1; i<=N; i++){las[que[i]] = i;if(fir[que[i]]==-1) fir[que[i]] = i;}bit.init(N);int np=0;for(int i=0; i<(int)Q.size(); i++){while(np<Q[i].r){np++;bit.add(pre[que[np]]+1, 1);bit.add(np+1, -1);pre[que[np]] = np;if(las[que[np]] == np){bit.add(1, -1);bit.add(fir[que[np]]+1, 1);}}ans[Q[i].id] = bit.sum(Q[i].l);}for(int i=0; i<N-1; i++) printf("%d\n", ans[i]);}return 0;
}void dfs(int u, int f)
{dfsn[u] = ++dfst;que[dfst] = col[u];for(int e=G.last[u], v; ~e; e=G.nxt[e]) if((v=G.v[e])!=f){id[v] = e>>1;dfs(v,u);}if(f) Q.push_back({dfsn[u], dfst, id[u]});
}

这篇关于[CSU - 1811 (湖南省赛16)] Tree Intersection (dfs序维护子树+离线询问+树状数组)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1082147

相关文章

csu(背包的变形题)

题目链接 这是一道背包的变形题目。好题呀 题意:给n个怪物,m个人,每个人的魔法消耗和魔法伤害不同,求打死所有怪物所需的魔法 #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>//#include<u>#include<map

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

hdu 2489 (dfs枚举 + prim)

题意: 对于一棵顶点和边都有权值的树,使用下面的等式来计算Ratio 给定一个n 个顶点的完全图及它所有顶点和边的权值,找到一个该图含有m 个顶点的子图,并且让这个子图的Ratio 值在所有m 个顶点的树中最小。 解析: 因为数据量不大,先用dfs枚举搭配出m个子节点,算出点和,然后套个prim算出边和,每次比较大小即可。 dfs没有写好,A的老泪纵横。 错在把index在d

poj 3050 dfs + set的妙用

题意: 给一个5x5的矩阵,求由多少个由连续6个元素组成的不一样的字符的个数。 解析: dfs + set去重搞定。 代码: #include <iostream>#include <cstdio>#include <set>#include <cstdlib>#include <algorithm>#include <cstring>#include <cm

ural 1149. Sinus Dances dfs

1149. Sinus Dances Time limit: 1.0 second Memory limit: 64 MB Let  An = sin(1–sin(2+sin(3–sin(4+…sin( n))…) Let  Sn = (…( A 1+ n) A 2+ n–1) A 3+…+2) An+1 For given  N print  SN Input One

hdu 6198 dfs枚举找规律+矩阵乘法

number number number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description We define a sequence  F : ⋅   F0=0,F1=1 ; ⋅   Fn=Fn

C语言:柔性数组

数组定义 柔性数组 err int arr[0] = {0}; // ERROR 柔性数组 // 常见struct Test{int len;char arr[1024];} // 柔性数组struct Test{int len;char arr[0];}struct Test *t;t = malloc(sizeof(Test) + 11);strcpy(t->arr,

C 语言基础之数组

文章目录 什么是数组数组变量的声明多维数组 什么是数组 数组,顾名思义,就是一组数。 假如班上有 30 个同学,让你编程统计每个人的分数,求最高分、最低分、平均分等。如果不知道数组,你只能这样写代码: int ZhangSan_score = 95;int LiSi_score = 90;......int LiuDong_score = 100;int Zhou