Description

NiroBC 姐姐是个活泼的少女,她十分喜欢爬树,而她家门口正好有一棵果树,正好满足了她爬树的需求。
这颗果树有N个节点,节点标号 1…N。每个节点长着一个果子,第i个节点上的果子颜色为 Ci 。
NiroBC姐姐每天都要爬树,每天都要选择一条有趣的路径 (u,v) 来爬。
一条路径被称作有趣的,当且仅当这条路径上的果子的颜色互不相同。
(u,v) 和 (v,u) 被视作同一条路径。特殊地,(i,i) 也被视作一条路径,这条路径只含 i 一个果子,显然是有趣的。
NiroBC姐姐想知道这颗树上有多少条有趣的路径。

Input

第一行,一个整数 N,表示果树的节点个数。
第二行,N 个整数 C1 ,C2 ,…,CN ,表示 N 个果子的颜色。
接下来 N−1 行,每行两个整数 ui ,vi ,表示 ui和vi 之间有一条边
数据保证这N−1条边构成一棵树。

Output

一个整数,表示有趣的路径的数量。

Sample Input

输入1:

3
1 2 3
1 2
1 3

输入2:

5
1 1 2 3 3
1 2
1 3
2 4
2 5

Sample Output

输出1:

6

样例解释:

有 (1,1),(1,2),(1,3),(2,2),(2,3),(3,3) 共 6 条有趣的路径。

输出2:

8

样例解释:

有 (1,1),(1,3),(2,2),(2,4),(2,5),(3,3),(4,4),(5,5) 共 8 条有趣的路径。

Data Constraint

Solution

  • 先贴题解:

  • 我们将每种颜色的点两两看做一组限制,在 N∗NN*N 平面上覆盖矩形。

  • 找“aia_i 下面的 pp 点”用倍增可以解决。

  • 设有某种颜色的点有 t (t≤20)t\ (t\le20) 个,那么复杂度就是 O(Nt∗t2 logN)=O(N∗t logN)O(\frac{N}{t}*t^2\ logN)=O(N*t\ logN) 。

  • 之后把每个矩形拆成两组(分别代表加入和删除),按x坐标排序,用扫描线扫过。

  • 维护一颗标记不下传的线段树,记录区间内空点的个数即可。

  • 时间复杂度 O(N∗t logN)O(N*t\ logN) 。

Code

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<cctype>
using namespace std;
const int N=1e5+5,M=21;
struct data
{int x,y1,y2,p;
}a[N*M<<2];
struct segment
{int sum,c;
}f[N<<2];
int n,tot,qx,qy,qz;
long long ans;
int first[N],nex[N<<1],en[N<<1];
int dfn[N],size[N],dep[N],fa[N][M];
vector<int>c[N];
inline int read()
{int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<1)+(X<<3)+(ch^48),ch=getchar();return w?-X:X;
}
inline void insert(int x,int y)
{nex[++tot]=first[x];first[x]=tot;en[tot]=y;
}
void dfs(int x)
{dfn[x]=++tot;dep[x]=dep[fa[x][0]]+1;size[x]=1;for(int i=first[x];i;i=nex[i])if(en[i]^fa[x][0]){fa[en[i]][0]=x;dfs(en[i]);size[x]+=size[en[i]];}
}
inline void cover(int x1,int y1,int x2,int y2)
{a[++tot]=(data){x1,y1,y2,1};a[++tot]=(data){x2+1,y1,y2,-1};
}
inline bool cmp(data x,data y)
{return x.x<y.x;
}
inline int getlca(int x,int y)
{for(int i=log2(dep[y]);i>=0;i--)if(dep[fa[y][i]]>dep[x]) y=fa[y][i];return y;
}
void make(int v,int l,int r)
{f[v].sum=r-l+1;if(l==r) return;int mid=l+r>>1;make(v<<1,l,mid);make(v<<1|1,mid+1,r);
}
void change(int v,int l,int r)
{if(qx<=l && r<=qy){f[v].c+=qz;if(f[v].c) f[v].sum=0; elseif(l==r) f[v].sum=1; elsef[v].sum=f[v<<1].sum+f[v<<1|1].sum;return;}int mid=l+r>>1;if(qx<=mid) change(v<<1,l,mid);if(qy>mid) change(v<<1|1,mid+1,r);if(!f[v].c) f[v].sum=f[v<<1].sum+f[v<<1|1].sum; else f[v].sum=0;
}
int main()
{freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);n=read();for(int i=1;i<=n;i++){int x=read();c[x].push_back(i);}for(int i=1;i<n;i++){int x=read(),y=read();insert(x,y);insert(y,x);}tot=0;dfs(1);for(int j=1;j<17;j++)for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1];tot=0;for(int i=1;i<=n;i++){int num=c[i].size();if(num>1)for(int j=0;j<num-1;j++)for(int k=j+1;k<num;k++){int x=c[i][j],y=c[i][k];if(dfn[x]>dfn[y]) swap(x,y);if(dfn[x]<dfn[y] && dfn[y]<=dfn[x]+size[x]-1){if(fa[y][0]==x){cover(1,dfn[y],dfn[y]-1,dfn[y]+size[y]-1);cover(dfn[y],1,dfn[y]+size[y]-1,dfn[y]-1);if(dfn[y]+size[y]<=n){cover(dfn[y]+size[y],dfn[y],n,dfn[y]+size[y]-1);cover(dfn[y],dfn[y]+size[y],dfn[y]+size[y]-1,n);}}else{int z=getlca(x,y);cover(1,dfn[y],dfn[z]-1,dfn[y]+size[y]-1);cover(dfn[y],1,dfn[y]+size[y]-1,dfn[z]-1);if(dfn[z]+size[z]<=n){cover(dfn[z]+size[z],dfn[y],n,dfn[y]+size[y]-1);cover(dfn[y],dfn[z]+size[z],dfn[y]+size[y]-1,n);}}}else{cover(dfn[x],dfn[y],dfn[x]+size[x]-1,dfn[y]+size[y]-1);cover(dfn[y],dfn[x],dfn[y]+size[y]-1,dfn[x]+size[x]-1);}}}sort(a+1,a+1+tot,cmp);make(1,1,n);for(int i=1,j=1;i<=n;i++){while(j<=tot && a[j].x==i){qx=a[j].y1,qy=a[j].y2,qz=a[j].p;change(1,1,n);j++;}ans+=f[1].sum;}printf("%lld",(ans+n)>>1);return 0;
}

JZOJ 5678. 【GDOI2018Day2模拟4.21】果树相关推荐

  1. JZOJ 5677. 【GDOI2018Day2模拟4.21】纽约

    Description 印度洋暖流温润着纽约,四季丰沛的雨水造就了一望无际的大草原.蒙古包是纽约最独特的一道风景线,每至二月中旬,纽约的土著傣族人民又开始半年一度的转场了. 由于牲畜和行李过多,牧民 ...

  2. JZOJ5677. 【GDOI2018Day2模拟4.21】纽约

    Description 印度洋暖流温润着纽约,四季丰沛的雨水造就了一望无际的大草原.蒙古包是纽约最独特的一道风景线,每至二月中旬,纽约的土著傣族人民又开始半年一度的转场了. 由于牲畜和行李过多,牧民 ...

  3. jzoj5920. 【NOIP2018模拟10.21】风筝(dp,最长上升子序列)

    5920. [NOIP2018模拟10.21]风筝 Description 当一阵风吹来,风筝飞上天空,为了你,而祈祷,而祝福,而感动-- Description oyiya 在 AK 了 IOI 之 ...

  4. JZOJ 5689. 【GDOI2018Day2模拟4.25】二进制

    Description Pupil 发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是3 的倍数.他想研究对于二进制,是否也有类似的性质.于是他生成了一个长为n的二进制串,希望你对于这 ...

  5. [JZOJ NOIP2018模拟10.21]

    考试之前我刚刚领略到了特判的重要性,没想到T2的两个子任务还是写挂了,丢了20分 考试的感觉不行,一路打的都是暴力,正解的思路想到一半就断了推不下去 T1:逛公园 题目链接: https://jzoj ...

  6. JZOJ 5691. 【GDOI2018Day2模拟4.25】求和

    Description master对树上的求和非常感兴趣.他生成了一棵有根树,并且希望多次询问这棵树上一段路径上所有节点深度的k次方和,而且每次的k可能是不同的.此处节点深度的定义是这个节点到根的路 ...

  7. JZOJ 5379. 【NOIP2017提高A组模拟9.21】Victor爱数字

    Description Victor 是一名热爱数字的同学.他最近在思考这样一个问题: 一个字符串是回文的当且仅当它倒过来还和原来相同.那么如果一个数的数串没有一个长度超过1 的子串是回文串的话,它就 ...

  8. JZOJ 4676. 【NOIP2016提高A组模拟7.21】模板串

    Description 科学家温斯顿从数据库中找到了一串相当长的字符串. 他正试图用一个模板串来重构这个字符串. 他可以将模板串复制多份,通过合适的方式拼接起来,使得最终的串与原串一致. 如果两个模板 ...

  9. JZOJ 4675. 【NOIP2016提高A组模拟7.21】Double-row

    Description 科学家温斯顿在一张超长的白纸上写下了两行数,每一行数有N个. 但他写完后觉得看起来有点不和谐.他希望重新编排,使得每一行数中没有相同的数. 他每次可以调换同一列的两个数. 请帮 ...

最新文章

  1. ARM 之八 Cortex-M/R 内核启动过程 / 程序启动流程(基于IAR)
  2. 八、关于防水透湿整理
  3. 使用代码对现实世界进行抽象,软件设计和思维。
  4. 查询英语单词 - 有道官方(一)
  5. 什么是内存碎片?如何避免?
  6. Windows10查看便签
  7. 第二次作业:微博案例分析
  8. 信用卡积分兑换里程全攻略
  9. 泰勒公式(泰勒展开式)通俗+本质详解
  10. Latex常用语法、语句、工具
  11. matlab读取声音文件
  12. 《Microduino实战》——2.7 总结
  13. Mac 搭建本地SVN,并使用Cornerstone管理svn
  14. 常用排序算法的c++实现(冒泡,选择,插入,堆,shell,快速,归并 )与sort()对比 - coder_xia的专栏 - 博客频道 - CSDN.NET...
  15. 【计算机视觉】张正友标定法相机标定
  16. if···else,switch-路程折扣题目
  17. 计算机化考试标准,2016年医师资格考试计算机化考试基地设置标准(试行)
  18. “同上”一堂课 科达为大连专递课堂公开会献策
  19. php 微信打赏功能,微信打赏是什么功能?微信怎么打赏?
  20. Mr.Alright---MTK平台Android Q去除虚拟按键并修改实体菜单键为换起最近任务

热门文章

  1. Python学习笔记:返回函数
  2. 使用matlab编译器生成EXE文件
  3. X Window、GNOME和KDE之间的关系
  4. IDEA中无法识别servlet类或找不到javax.servlet.*
  5. C++ OJ在线编程常见输入输出技巧与示例
  6. 科大星云诗社动态20210328
  7. ODS:输出多样化采样,有效增强白盒和黑盒攻击的性能 | NeurIPS 2020
  8. JavaScript 中的内存泄露模式
  9. C++/CLI Winform中调用DLL的三种方法
  10. 用键盘全局钩子[Hook]监视多进程键盘操作