【树状数组】CSU 1811 Tree Intersection (2016湖南省第十二届大学生计算机程序设计竞赛)
题目链接:
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1811
题目大意:
一棵树,N(2<=N<=105)个节点,每个节点有一种颜色Ci(Ci<=N),问把每一条边删掉后,剩下的两个联通块中颜色的交集的大小(就是两边都含有的颜色种数)。
题目思路:
【树状数组】
我的数据结构造诣不深,这题写了暴力求每个点的颜色数T了。看了别人的题解写了超级久WA了好多才过。
首先可以知道,如果已知每个节点的子树中含有的颜色种数C和只出现在这棵子树的颜色种数D,那么这个节点和它的父亲节点中间的那条边被删去后的答案就是C-D。
所以问题变为求以每个节点为根的子树中的C和D值。然后我想到这里就不知道要怎么写了。看了大神的题解才有一点思路。(不过我感觉大神的题解好像有点问题??)
首先转化成dfs序,按照遍历这棵树的顺序求出每个节点的新的从小到大的标号q[u].b(父亲标号先前于儿子),同时记下原先对应的节点标号q[u].id
预处理出对于颜色ci,记pre[ci]为ci上次出现的颜色位置,L[ci],R[ci]为ci出现的最左最右端。然后按照新的dfs序标号从小到大做
对于节点i,将pre[ci]到i之间的所有点ans+1(因为答案是一条条树链统计的,不会计算到兄弟节点,实际影响的只有这个节点以上的父亲节点,所以答案不会出错,本质上相当于把L[ci]到R[ci]所有的点都ans+1,但是只有有这种颜色的节点到根的树链上的点会加上答案,这样其实是没错的)
如果到了颜色的最右端,把这种颜色最左端左边的答案删掉(因为一开始pre默认是0,会把1~L[ci]中的答案+1,需要扣除,也可以一开始就从L[ci]开始加)
到达叶子结点后统计这条树链的答案。以上的ans可以用树状数组统计。
//
//by coolxxx
//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<iomanip>
#include<map>
#include<stack>
#include<queue>
#include<set>
#include<bitset>
#include<memory.h>
#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//#include<stdbool.h>
#include<math.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(a) ((a)>0?(a):(-(a)))
#define lowbit(a) (a&(-a))
#define sqr(a) ((a)*(a))
#define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
#define mem(a,b) memset(a,b,sizeof(a))
#define eps (1e-10)
#define J 10000
#define mod 1000000007
#define MAX 0x7f7f7f7f
#define PI 3.14159265358979323
#pragma comment(linker,"/STACK:102400000,102400000")
#define N 100004
#define M 200004
using namespace std;
typedef long long LL;
int cas,cass;
int n,m,lll,ans;
double anss;
LL aans;
int last[N],fa[N],c[N],pre[N],l[N],r[N],f[N],g[N],e[N];
struct edge
{
int from,next,to;
}a[M];
struct xu
{
int b,id;
}q[N];
void add(int x,int y)
{
a[++lll].to=y;
a[lll].from=x;
a[lll].next=last[x];
last[x]=lll;
}
bool cmp(xu aa,xu bb)
{
return aa.b<bb.b;
}
void dfs(int u,int father)
{
int i,v;
q[u].b=++cas,q[u].id=u;//b为新的按照dfs顺序的标号,id为原先标号
for(i=last[u];i;i=a[i].next)
{
v=a[i].to;
if(v==father)continue;
dfs(v,u);
e[q[v].b]=(i+)>>;//把新节点标号和原先的边的标号对应起来
fa[q[v].b]=q[u].b;//统计新节点标号的父亲
}
}
inline void modify(int x,int y)
{
int i;
for(i=x;i<=n;i+=lowbit(i))f[i]+=y;
}
inline int getsum(int x)
{
int i,sum=;
for(i=x;i;i-=lowbit(i))sum+=f[i];
return sum;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
#endif
int i,j,k;
int x,y,z;
// init();
// for(scanf("%d",&cass);cass;cass--)
// for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
// while(~scanf("%s",s))
while(~scanf("%d",&n))
{
lll=cas=;mem(last,);mem(l,);mem(r,);mem(pre,);mem(f,);
for(i=;i<=n;i++)scanf("%d",c+i);
for(i=;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(,);
sort(q+,q++n,cmp);
for(i=,j=q[i].id;i<=n;i++,j=q[i].id)
if(!l[c[j]])l[c[j]]=i;//统计每种颜色出现的最左端
for(i=n,j=q[i].id;i;i--,j=q[i].id)
if(!r[c[j]])r[c[j]]=i;//统计每种颜色出现的最右端
for(i=;i<=n;i++)
{
j=q[i].id;
modify(pre[c[j]]+,),modify(i+,-);//把上次这个颜色出现的位置到i之间的节点答案+1
pre[c[j]]=i;//pre记录的是这个颜色上一次出现的位置
if(i==r[c[j]])modify(,-),modify(l[c[j]]+,);//如果这种颜色出现最右端在这个点,那么把最左端左边的所有节点答案-1,因为颜色最左端的答案不能统计在内
if(a[last[j]].to==q[fa[i]].id)//如果当前结点是叶子结点
for(k=i;k!=;k=fa[k])g[e[k]]=getsum(k);//统计从根到这个叶子结点的树链的答案
}
for(i=;i<n;i++)
printf("%d\n",g[i]);
}
return ;
}
/*
// //
*/
【树状数组】CSU 1811 Tree Intersection (2016湖南省第十二届大学生计算机程序设计竞赛)的更多相关文章
- 【贪心】CSU 1809 Parenthesis (2016湖南省第十二届大学生计算机程序设计竞赛)
题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1809 题目大意: 给一个长度为N(N<=105)的合法括号序列.Q(Q<= ...
- 【模拟】【数学】CSU 1803 2016 (2016湖南省第十二届大学生计算机程序设计竞赛)
题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1803 题目大意: 给定n,m(n,m<=109)1<=i<=n,1& ...
- 【模拟】CSU 1807 最长上升子序列~ (2016湖南省第十二届大学生计算机程序设计竞赛)
题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1807 题目大意: 给你一个长度为N(N<=105)的数列,数列中的0可以被其他数 ...
- 【最短路】【数学】CSU 1806 Toll (2016湖南省第十二届大学生计算机程序设计竞赛)
题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1806 题目大意: N个点M条有向边,给一个时间T(2≤n≤10,1≤m≤n(n-1), ...
- 【数学】CSU 1810 Reverse (2016湖南省第十二届大学生计算机程序设计竞赛)
题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1810 题目大意: 一个长度为N的十进制数,R(i,j)表示将第i位到第j位翻转过来后的 ...
- 【拓扑】【宽搜】CSU 1084 有向无环图 (2016湖南省第十二届大学生计算机程序设计竞赛)
题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1804 题目大意: 一个有向无环图(DAG),有N个点M条有向边(N,M<=105 ...
- 【最短路】【STL】CSU 1808 地铁 (2016湖南省第十二届大学生计算机程序设计竞赛)
题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1808 题目大意: N个点M条无向边(N,M<=105),每条边属于某一条地铁Ci ...
- 2016年湖南省第十二届大学生计算机程序设计竞赛---Parenthesis(线段树求区间最值)
原题链接 http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1809 Description Bobo has a balanced parenthes ...
- 2016年湖南省第十二届大学生计算机程序设计竞赛Problem A 2016 找规律归类
Problem A: 2016 Time Limit: 5 Sec Memory Limit: 128 MB Description 给出正整数 n 和 m,统计满足以下条件的正整数对 (a,b) ...
随机推荐
- Oracle中wm_concat()的使用方法
以下两种方式使用wm_concat()的使用方法是等效的. 方法一:使用窗口函数,wm_concat支持窗口函数 select distinct classKey,className, classOr ...
- 客户端session与服务端session
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...
- react初识
如下是在研究中记录的笔记: 1,作用:局部的更新dom结构;虚拟dom保证性能2,和mvc不同,mvc是对于技术上的分离(分类),而react是组件上的分离,每个视图模块分离,复用,以视图模块为单位3 ...
- Android开发手记(28) Handler和Looper
Android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道.平 ...
- Android TV 模拟器启动
模拟器启动错误 使用IntelCPU的模拟器 http://software.intel.com/en-us/android/articles/intel-hardware-accelerated-e ...
- 读懂IL代码(一)
以前刚开始学C#的时候,总有高手跟我说,去了解一下IL代码吧,看懂了你能更加清楚的知道你写出来的代码是如何运行互相调用的,可是那时候没去看,后来补的,其实感觉也不晚.刚开始看IL代码的时候,感觉非常吃 ...
- javascript事件详解1
事件流讲解来袭,嘎嘎嘎嘎嘎 ---------------------------------------------------------------- 1.事件流:描述的是在页面中接受事件的顺序 ...
- ios开发之xcode6中如何添加pch全局引用文件
xcode6中去掉了默认添加pch文件,这就需要我们自己手动添加pch文件了,添加pch文件是为了一些琐碎的头文件引用,加快编译速度! 下面就说下该如何手动添加pch文件: 1.添加一个文件,在oth ...
- Devexpress Barmanager设置
一,在bar的属性中有optionbar,可以做一些设置. 其中比较有用的是:1,去掉最右边的箭头:allowquickcustomization 改为false 2,去掉最左边的竖线:drawdra ...
- Android安装 sdk+jdk+Eclipse+Adt开发工具
根据别人提供的手册和安装过程体验加以更新和详细描述 安装Android开发工具 开发Android应用程序的门坎并不高,因为Google已经为Android应用程序开发提供了免费而且跨平台的集成开发环 ...